<?php

namespace Application\Service\Extension\Helper\components;

use Application\Common\RedisEnum;
use Application\Service\DB\Dictionary\Form;
use Application\Service\DB\Dictionary\FormGroup;
use Application\Service\DB\Item\PatientFormContent;
use Application\Service\Extension\Helper\ArrayHelper;
use Application\Service\Extension\Helper\base\BaseHelper;
use Application\Service\Extension\Helper\SDMHelper;
use Application\Service\Extension\Helper\StringHelper;
use Application\Service\Extension\Laminas;
use Application\Service\Extension\Uploader\adapter\Oss;
use Exception;
use Laminas\Db\Sql\Expression;
use Laminas\Db\Sql\Predicate\Like;
use Laminas\Db\Sql\Predicate\In;
use Laminas\Db\Sql\Predicate\NotIn;
use Laminas\Json\Json;

/**
 * @property-write  $contentId
 */
class FormContentHelper extends BaseHelper
{
    protected ?int $contentId = null;

    /**
     * 未处理过的数据
     * @var array|null
     */
    protected ?array $postContentOriginData = null;

    protected ?int $checktimeId = null;
    protected ?int $itemsigId = null;

    /** @var string 删除事件 */
    const EVENT_EDIT = 'EVENT_EDIT';

    const EVENT_CREATE = 'EVENT_CREATE';

    const HELPER_KEY_IS_EDC_LOCK = 'IS_EDC_LOCK';

    const CONTENT_TYPE_FORM = 'form';
    const CONTENT_TYPE_AE = 'ae';

    protected array $contentDbServiceList;
    protected string $contentType;
    public function __construct($config = [])
    {
        parent::__construct($config);

        $this->initService();

        // 默认为基本表单内容服务
        $this->setContentType(self::CONTENT_TYPE_FORM);
    }

    private function initService() {
        $this->contentDbServiceList = [
            self::CONTENT_TYPE_FORM  => 'patientFormContent',   // 基本表单内容服务
            self::CONTENT_TYPE_AE    => 'itemPatientAeContent'  // AE表单内容服务
        ];
    }

    public function setContentType(string $conentType): FormContentHelper
    {
        $this->contentType = $conentType ;
        return $this;
    }

    protected function getContentDbService() {
        return $this->contentDbServiceList[$this->contentType];
    }

    protected function getCache(string $helperKey = self::HELPER_KEY_BASE)
    {
        return self::$cache[$this->getCacheKey()][$this->contentId][$helperKey] ?? [];
    }

    protected function getCacheKey(): string
    {
        return self::class . $this->contentType;
    }

    protected function _getCacheData(): array
    {
        if (!$this->getCache()) {
            $this->setCache(Laminas::$serviceManager->{$this->getContentDbService()}->fetchOne([
                'where' => ['id' => $this->contentId]
            ]));
        }

        return $this->getCache();
    }

    /**
     * @note 获取
     * @param int $content_id
     * @param int $field_id
     * @return string
     * @throws Exception
     */
    public function getUploadFiles(int $content_id, int $field_id): string
    {
        $uploadFiles = $this->getDecodeData($content_id)[$field_id] ?? [];

        if(empty($uploadFiles)) {
            // 从附件表中获取
            $uploadFiles = Json::encode(Laminas::$serviceManager->patientFormContentImg->fetchAll([
                'where' => [
                    'content_id' => $content_id,
                    'field_id' => $field_id,
                    'item_id' => $this->getItemId(),
                    'form_id' => $this->getFormId(),
                    'patient_id' => $this->getPatientId(),
                    'itemsig_id' => $this->getItemsigId(),
                    'is_del' => 0
                ],
                'columns' => [
                    'url' => new Expression("CONCAT( '". Oss::getUploadDomain()."' , img_src)"), 'name' => 'img_name'
                ]
            ]));
        }

        return $uploadFiles;
    }

    /**
     * 获取项目id
     * @return int
     * @throws Exception
     */
    public function getItemId(): int
    {
        $val = $this->_getCacheData();
        return $this->getProperty($val, 'item_id');
    }

    /**
     * 获取受试者id
     * @return int
     * @throws Exception
     */
    public function getPatientId(): int
    {
        $val = $this->_getCacheData();

        return $this->getProperty($val, 'patient_id');
    }

    /**
     * 获取表单id
     * @return int
     * @throws Exception
     */
    public function getFormId(): int
    {
        $val = $this->_getCacheData();

        return $this->getProperty($val, 'form_id');
    }

    /**
     * @throws Exception
     */
    public function getFormGroupId(): int
    {
        return Laminas::$serviceManager->itemForm->getOneFieldVal('group_id', 'id = ' . $this->getFormId());
    }

    /**
     * 获取检查点
     * @return int
     * @throws Exception
     */
    public function getCheckTimeId(): int
    {
        if ($this->checktimeId === null) {
            $this->checktimeId = $this->_getCacheData()['checktime_id'] ?? 0;
        }


        return $this->getProperty($this->checktimeId);
    }

    /**
     * @throws Exception
     */
    public function getItemsigId(): int
    {
        if ($this->itemsigId === null) {
            $this->itemsigId = $this->_getCacheData()['itemsig_id'] ?? 0;
        }


        return $this->getProperty($this->itemsigId);
    }

    public function getDelete() {
        return Laminas::$serviceManager->itemPatientFormContentDelete->fetchOne([
            'where' => ['content_id' => $this->contentId]
        ]);
    }

    /**
     * 获取表单数据
     * @return int
     * @throws Exception
     */
    public function getData(): string
    {
        $val = $this->_getCacheData();

        return $this->getProperty($val, 'data');
    }

    /**
     * 获取表单decode后的数据
     * @return mixed
     * @throws Exception
     */
    public function getDecodeData(int $contentId)
    {
        if ($contentId) {
            $this->contentId = $contentId;
        }

        $val = StringHelper::jsonDecode($this->getData());

        return $this->getProperty($val);
    }

    /**
     * @note 是否已删除（0、否；1、是）
     * @throws Exception
     */
    public function isDel(int $contentId = 0) {
        if ($contentId) {
            $this->contentId = $contentId;
        }
        $val = $this->_getCacheData();

        return $this->getProperty($val, 'is_del');
    }

    /**
     * 主键id
     * @return mixed
     * @throws Exception
     */
    public function getContentId(int $contentId = null)
    {
        if ($contentId) {
            $this->contentId = $contentId;
        }

        $val = $this->_getCacheData();

        return $this->getProperty($val, 'id');
    }

    /**
     * 中心id
     * @return mixed
     * @throws Exception
     */
    public function getSignId()
    {
        $val = $this->_getCacheData();

        return $this->getProperty($val, 'itemsig_id');
    }

    public function getIsComplete(?int $contentId = 0) {
        if ($contentId) {
            $this->contentId = $contentId;
        }

        $val = $this->_getCacheData();

        return $this->getProperty($val, 'is_complete');
    }

    /**
     * 将表单内容先暂存起来
     * @param array $content
     * @param int $patient
     * @param int $checkTimeId
     * @param int $formId
     * @return bool
     */
    public function setTempStorage(array $content, int $patient = 0, int $checkTimeId = 0, int $formId = 0): bool
    {
        $key = RedisEnum::PATIENT_FORM_TEMP_STORAGE . md5("{$patient}{$checkTimeId}{$formId}");
        return Laminas::$serviceManager->redisExtend->getRedisInstance()->set($key, json_encode($content));
    }

    public function setMultiTempStorage(array $content, int $patient = 0, int $checkTimeId = 0, int $formId = 0, $updateIndex = false)
    {
        $key = RedisEnum::PATIENT_FORM_TEMP_STORAGE . md5("{$patient}{$checkTimeId}{$formId}");

        $method = $updateIndex ? 'lSet' : 'rPush' ;
        if ($method === 'lSet') {
            return Laminas::$serviceManager->redisExtend->getRedisInstance()->lSet($key, $updateIndex - 1, json_encode($content));
        } elseif ($method === 'rPush') {
            return Laminas::$serviceManager->redisExtend->getRedisInstance()->rPush($key, json_encode($content));
        }
    }

    /**
     * 获取暂存的表单数据
     * @param int $patient
     * @param int $checkTimeId
     * @param int $formId
     * @return string
     */
    public function getTempStorage(int $patient = 0, int $checkTimeId = 0, int $formId = 0): string
    {
        $key = RedisEnum::PATIENT_FORM_TEMP_STORAGE . md5("{$patient}{$checkTimeId}{$formId}");
        return Laminas::$serviceManager->redisExtend->getRedisInstance()->get($key);
    }

    /**
     * 获取暂存的表单数据
     * @param int $patient
     * @param int $checkTimeId
     * @param int $formId
     * @return string
     */
    public function getMultiTempStorage(int $patient = 0, int $checkTimeId = 0, int $formId = 0): array
    {
        $key = RedisEnum::PATIENT_FORM_TEMP_STORAGE . md5("{$patient}{$checkTimeId}{$formId}");
        return Laminas::$serviceManager->redisExtend->getRedisInstance()->lrange($key, 0, -1);
    }

    public function removeTempStorage(int $patient = 0, int $checkTimeId = 0, int $formId = 0): int
    {
        $key = RedisEnum::PATIENT_FORM_TEMP_STORAGE . md5("{$patient}{$checkTimeId}{$formId}");
        return Laminas::$serviceManager->redisExtend->getRedisInstance()->del($key);
    }

    /**
     * 是否锁定
     * @return mixed
     * @throws Exception
     */
    public function getIsLock(int $contentId)
    {
        if ($contentId) {
            $this->contentId = $contentId;
        }

        $val = $this->_getCacheData();

        return $this->getProperty($val, 'is_lock');
    }

    public function getUpdateTime(int $contentId)
    {
        if ($contentId) {
            $this->contentId = $contentId;
        }

        $val = $this->_getCacheData();

        return $this->getProperty($val, 'update_time');
    }

    public function getUpdateUserId(int $contentId)
    {
        if ($contentId) {
            $this->contentId = $contentId;
        }

        $val = $this->_getCacheData();

        return $this->getProperty($val, 'update_user_id');
    }

    public function unlock(int $contentId)
    {
        if ($contentId) {
            $this->contentId = $contentId;
        }

        return Laminas::$serviceManager->patientFormContent->update(['is_del' => 0], ['id' => $contentId]);
    }

    public function getIsEdcLock(): bool
    {
        if (!$this->getCache(self::HELPER_KEY_IS_EDC_LOCK)) {
            $isLock = Laminas::$serviceManager->projectPatientworkinfo->memoryCache()->fetchOne([
                    'where' => [
                        'form_id' => $this->getFormId(),
                        'patient_id' => $this->getPatientId(),
                        'content_id' => $this->contentId,
                        'is_del' => 0,
                        new In('edc_lock', [1,2])
                    ]
                ]) ?? false;

            $this->setCache((bool)$isLock, self::HELPER_KEY_IS_EDC_LOCK);
        }

        return (bool)$this->getCache(self::HELPER_KEY_IS_EDC_LOCK);
    }

    /**
     * 当前表单是否正在申请解锁
     * @param int $patientId
     * @param int $checktimeId
     * @param int $formId
     * @return bool|mixed|string
     * @throws Exception
     */
    public function getIsWaitingUnLock(int $patientId, int $checktimeId, int $formId)
    {
        if (SDMHelper::app()->form->getGroupId($formId) == FormGroup::NORMAL_OCR) {
            $itemId = SDMHelper::app()->form->getItemId($formId);
            $sharePool = SDMHelper::app()->form->getGcoPool($formId);
            $values = Laminas::$serviceManager->redisExtend->getRedisInstance()->hGet("UNLOCK_SHARE_FORM:{$itemId}", "{$patientId}:{$checktimeId}:{$sharePool}");
            if ($values) {
                $values = StringHelper::jsonDecode($values);
            }

            //return isset($values[$formId]);
            return !empty($values);
        }

    }

    public function getShareImages(?int $contentId = 0, string $imgPath = '') : array
    {
        $imgPath = $imgPath ?: "{$_SERVER['REQUEST_SCHEME']}://{$_SERVER['HTTP_HOST']}/common/showPic?path=";
        if ($contentId) {
            $this->contentId = $contentId;
        }

        // 共享表单id集合
        $shareFormIdList = ArrayHelper::getColumn(SDMHelper::app()->form->getGcoGroupForm($this->getFormId()), 'id');

        // 获取当前表单所有的共享图片列表
        $shareImgList = Laminas::$serviceManager->patientFormContentImg->fetchAll([
            'where' => [
                'item_id' => $this->getItemId(),
                'itemsig_id' => $this->getItemsigId(),
                'patient_id' => $this->getPatientId(),
                'checktime_id' => $this->getCheckTimeId(),
                'form_id' => $shareFormIdList,
                'is_del' => 0
            ],
            'columns' => [
                'url' => new Expression("concat(?, img_src)", $imgPath),
                'name' => 'img_name'
            ],
        ]);

        return $shareImgList;
    }

    protected function setCache($value, string $helperKey = self::HELPER_KEY_BASE)
    {
        self::$cache[$this->getCacheKey()][$this->contentId][$helperKey] = $value;
    }
}