<?php

namespace Application\Service\Extension\CheckLogic;



use Application\Service\DB\Dictionary\FormField;
use Application\Service\DB\Dictionary\FormGroup;
use Application\Service\Exceptions\InvalidArgumentException;
use Application\Service\Extension\CheckLogic\plugins\Required;
use Application\Service\Extension\ErrorHandler;
use Application\Service\Extension\Helper\ArrayHelper;
use Application\Service\Extension\Helper\DataHelper;
use Application\Service\Extension\Helper\SDMHelper;
use Application\Service\Extension\Helper\StringHelper;
use Application\Service\Extension\Helper\VarDumperHelper;
use Application\Service\Extension\HelperV2\Helper;
use Application\Service\Extension\Laminas;
use Application\Service\Extension\Params\Params;
use Laminas\Db\Sql\Predicate\Operator;

require_once 'Functions.php';

/**
 * 逻辑核查~~~
 */
class CheckLogicApplication
{
//    use Functions;

    public const CONDITIONS = [
        '不等于' => ' != ',
        '大于等于' => ' >= ',
        '小于等于' => ' <= ',
        '等于' => ' == ',
        '大于`>`' => ' > ',
        '小于`<`' => ' < ',
        '并且' => ' && ',
        '或者' => ' || ',
        '减`-`' => ' - ',
        '加`+`' => ' + ',
        '乘`*`' => ' * ',
        '除`/`' => ' / ',
        '左括号`(`' => ' ( ',
        '右括号`)`' => ' ) ',
    ];

    public const VAR_MARKS_LEFT = '`';
    public const VAR_MARKS_RIGHT = '`';

    private ?ExpressionGenerator $generator = null;

    /**
     * 逻辑核查公式
     * @var string
     */
    public string $logicExpression = '';

    /**
     * 逻辑核查公式id
     * @var string
     */
    public string $logicExpressionId = '';

    /**
     * 检查点id
     * @var int|null
     */
    private int $checkTimeId = 0;

    private int $itemId = 0;

    private array $patientId = [];

//    private array $dataProvider = [];
    public static array $dataProvider = [];

    public array $versionData = [];

    private array $errors = [];

    public static bool $debugMode = false;

    private ?int $executePatientId = null;
    private int $executeMultiId = 0;
    private int $executeMultiIndex = 0;
    private int $executeSignId = 0;
    private ?int $executeCheckTimeId = null;
    private ?int $executeFormId = null;

    private array $varCache = [];

    private array $varFormIdCache = [];

    private array $fieldCache = [];

    private array $pluginContainer = [];

    private array $fieldnote = [];

    private int $formContentId = 0;

    public static function debugPrint($msg)
    {
        if (self::$debugMode === true) {
            echo ($msg) . PHP_EOL;
        }
    }

    /**
     * 设置项目id
     * @param int $itemId
     * @return $this
     */
    public function setItemId(int $itemId): CheckLogicApplication
    {
        $this->itemId = $itemId;
        return $this;
    }


    /**
     * Notes:设置content_id
     * @param
     * @return
     * @author haojinhua
     * @date 2025-05-06
     */
    public function setContentId($contentPrimaryKey)
    {
        $this->formContentId = $contentPrimaryKey;
        return $this;
    }

    public function setPatientId($patientId)
    {
        if (is_array($patientId)) {
            $this->patientId = $patientId;
        } else {
            $this->patientId = (array)$patientId;
        }

        return $this;
    }

    /**
     * @param $data
     * @return $this
     */
    public function setDataProvider($data): CheckLogicApplication
    {
        self::$dataProvider = $data;
        return $this;
    }

    public function setGenerator(ExpressionGenerator $generator): CheckLogicApplication
    {
        $this->generator = $generator;
        $this->logicExpression = $generator->expression;
        return $this;
    }

    public function setDatanote($note_arr)
    {
        $this->note_arr = $note_arr;
        return $this;
    }

    /**
     * 生成核查表达式
     * @return string
     */
    public function generateExpression(): string
    {
        $generator = new ExpressionGenerator();
        $this->logicExpression = $generator->generate($this->logicExpression);
        return $this->logicExpression;
    }

    public static function formatVar($var)
    {
        return str_replace([CheckLogicApplication::VAR_MARKS_LEFT, CheckLogicApplication::VAR_MARKS_RIGHT], '', $var);
    }

    public static function formatPattern(string $pattern = '/\VAR_MARKS_LEFT.*?\VAR_MARKS_RIGHT/')
    {
        return str_replace(['VAR_MARKS_LEFT','VAR_MARKS_RIGHT'], [self::VAR_MARKS_LEFT, self::VAR_MARKS_RIGHT], $pattern);
    }

    private function getExecuteList(): array
    {
        $c = [
            'item_id' => $this->generator->itemId,
        ];

        // 指定了受试者
        if ($this->patientId) {
            $c['id'] = $this->patientId;
        }

        return ArrayHelper::index(Laminas::$serviceManager->patient->fetchAll([
            'columns' => ['id', 'itemsig_id'],
            'where' => $c
        ]), 'id');
//        return Laminas::$serviceManager->patient->fetchCol('id', $c);
    }

    private function getFormId(string $varName)
    {
        if (!isset($this->fieldCache[$varName])) {
            $this->setFieldCache($varName);
        }

        return $this->fieldCache[$varName]['form_id'] ?? false;
    }

    private function getFieldId(string $varName)
    {
        if (!isset($this->fieldCache[$varName])) {
            $this->setFieldCache($varName);
        }

        return $this->fieldCache[$varName]['fieldId'] ?? false;
    }

    // 获取version数据
    public function getFieldType(int $formId)
    {
        if (!isset($this->versionData[$formId])) {
            $this->setVersionData($formId);
        }

        return $this->versionData[$formId] ?? false;
    }

    private function setVersionData(int $formId)
    {
        $this->versionData[$formId] = Laminas::$serviceManager->itemFormVersion->getField(['form_id' => $formId], true);
    }

    private function setFieldCache(string $varName)
    {
        $query = Laminas::$serviceManager->itemFormField->fetchOne([
                'where' => [
                    'var_name' => $varName,
                    'item_id' => $this->generator->itemId
                ]
            ]) ?? false;

        if ($query) {
            $this->fieldCache[$varName]['fieldId'] = $query['id'];
            $this->fieldCache[$varName]['form_id'] = $query['form_id'];
        }
    }

    public static function formatVal($type, $val)
    {
        if ($type == -1) {
            return $val;
        }

        if ($val === '') {
            return "";
        }

        if ($type == FormField::FORM_FIELD_TYPE_DATE) { // 年月日
            return strtotime($val);
        } elseif ($type == FormField::FORM_FIELD_TYPE_TEXT) { // 文本类型
            return "{$val}";
        } elseif ($type == FormField::FORM_FIELD_TYPE_FLOAT_1) { // 保留一位小数
            $val = floatval($val);
            return floor($val * 10) / 10;
        } elseif ($type == FormField::FORM_FIELD_TYPE_FLOAT_2) { // 保留两位小数
            $val = floatval($val);
            return floor($val * 100) / 100;
        } elseif ($type == FormField::FORM_FIELD_TYPE_FLOAT_3) { // 保留三位小数
            $val = floatval($val);
            return floor($val * 1000) / 1000;
        } elseif ($type == FormField::FORM_FIELD_TYPE_DATE_SECOND) { // 年月日时分秒
            return strtotime($val);
        } elseif ($type == FormField::FORM_FIELD_TYPE_DATETIME) { // 年月日时分
            return strtotime($val);
        } elseif ($type == FormField::FORM_FIELD_TYPE_INTEGER) { // 整数类型
            return intval($val);
        } elseif ($type == FormField::FORM_FIELD_TYPE_DATE_UK) { // UK日期类型
            // 包含uk
            if (stripos($val, 'UK') !== false) {
                throw new InvalidValException('当前日期类型无法解析');
            }

            list($year, $month, $day) = explode('-', $val);
            if ($year && $month && $day) {
                return strtotime("{$year}-{$month}-{$day}");
            }

            throw new InvalidValException('当前日期类型无法解析');
        }

        return $val;
    }

    private function arrayToString($obj)
    {
        //prt($obj);
        $objType=gettype($obj);
        if ($objType=='array') {
            $objstring = "array(";
            foreach ($obj as $objkey=>$objv)
            {
                $objstring .="\"$objkey\"=>";
                $vtype =gettype($objv);
                if ($vtype=='integer') {
                    $objstring .="$objv,";
                }else if ($vtype=='double'){
                    $objstring .="$objv,";
                }else if ($vtype=='string'){
                    $t = stripslashes($objv);
                    $objv = str_replace("\t","\\t",$t);
                    $objv = str_replace("\n","\\n" , $objv);
                    $objv = str_replace("\r","\\r" , $objv);
                    $objv = str_replace("\"","\\\"" , $objv);
                    $objstring .="\"".$objv."\",";
                }else if ($vtype=='array'){
                    $objstring .=$this->arrayToString($objv).",";
                }else if ($vtype=='object'){
                    $objstring .=$this->arrayToString($objv).",";
                }else {
                    //值为空等其他情况
                    //echo "[$vType]".$objv."=".$objkey;
                    $objstring .="\"".$objv."\",";
                }
            }
            $objstring = substr($objstring,0,-1);
            return $objstring.")\n";
        }
    }

    /**
     * 获取eval表达式
     * @param string $code
     * @return string
     */
    private function getEvalCode(string $code): string
    {
//        $varCache = $this->arrayToString($this->varCache);
        if (!self::$dataProvider) {
            $GLOBALS['varCache'] = $this->fieldCache;
            $GLOBALS['generator'] = $this->generator;
            $GLOBALS['patientId'] = $this->executePatientId;
            $GLOBALS['multiId'] = $this->formContentId;
            $GLOBALS['itemId'] = $this->itemId;
        }
        return <<<EOF
    \$app = function () {
        return $code;
    };
    
    \$isSuccess = (bool)\$app();
EOF;
    }

    private function getExecuteCode($var, $code)
    {

        $pattern = self::formatPattern();
        preg_match_all($pattern, $code, $matchVars);

        if (!$matchVars) {
            return $code;
        }

        foreach ($matchVars[0] as $v) {
            if (!isset($var[$v])) {
                $var[$v] = [
                    'val' => 'null'
                ];
            }
        }

        // 防止替换错了
        foreach ($var as  $k => $item) {
            if (is_numeric($k)) {
                unset($var[$k]);
            }
        }
        return str_replace(array_keys($var), ArrayHelper::getColumn($var, 'val'), $code);
    }

    private function executeSuccessHandler()
    {
        //需要循环表单存储
        $usingInfos = $this->generator->allusings;
        $content_where = $timeFormFieldArr = $oldError_where = [];
        //查询该项目下贯穿全程类表单
        $form_group_arr = Laminas::$serviceManager->itemForm->fetchCol('group_id',[
            'is_del' => 0,
            'item_id' => $this->generator->itemId
        ]);
        if(!empty($usingInfos)) {
            foreach ($usingInfos as $usingInfo) {
                $info = explode('_', $usingInfo);
                if (!empty($info)) {
                    $oldError_where['or'][] = [
                        'checktime_id' => $info[0],
                        'form_id' => $info[1],
                        'prop' => $info[2],
                    ];
                }
            }
        }
        //获取历史已存储的逻辑核查公式质疑信息
        $oldErrorwhere = [
            'is_del' => 0,
            'error_type' => 0,
            'item_id' => $this->generator->itemId,
            'patient_id' => $this->executePatientId,
            $oldError_where,
        ];

        if(isset($this->formContentId) && !empty($this->formContentId)){
            $oldErrorwhere['multi_id'] =  $this->formContentId;
        }
        $oldErrorDatas = Laminas::$serviceManager->itemPatientFormLogicErrorPointer->fetchAll([
            'where'=> $oldErrorwhere,
            'columns'=>['id','error_id','checktime_id','form_id','prop','multi_id']
        ]);

        $updateTimeFormArr = [];
        if(!empty($oldErrorDatas)){
            //查询关闭的质疑ID
            $closed_erroridArr = Laminas::$serviceManager->itemPatientFormLogicError->fetchCol('id',[
                'is_del' => 0,
                'is_closed' => 1,
                'item_id' => $this->generator->itemId,
                'patient_id' => $this->executePatientId,
            ]);
            $check_erroridArr = Laminas::$serviceManager->itemPatientFormLogicError->fetchCol('id',[
                'is_del' => 0,
                'is_report' => 1,
                'item_id' => $this->generator->itemId,
                'patient_id' => $this->executePatientId,
            ]);
            foreach ($oldErrorDatas as $oldErrorData){
                if(!in_array($oldErrorData['error_id'],$closed_erroridArr)){ //未关闭的质疑进行关闭
                    Laminas::$serviceManager->itemPatientFormLogicError->update(['is_closed' => 1,'update_user_id' => 0], ['id' => $oldErrorData['error_id']]);
                    //插入关闭质疑的沟通记录
                    Laminas::$serviceManager->itemPatientFormLogicErrorQuery->save([
                        'content' => '关闭质疑',
                        'error_id' => $oldErrorData['error_id'],
                        'platform' => 1,
                        'is_reply' => 1,
                        'pointer_id' => $oldErrorData['id'],
                        'item_id' => $this->itemId,
                        'create_user_id' => 0 // 系统
                    ]);
                    //log表增加关闭记录
                    Laminas::$serviceManager->itemPatientFormLogicErrorLog->save([
                        'error_id'       => $oldErrorData['error_id'],
                        'is_error'       => 0,
                        'item_id'        => $this->generator->itemId,
                        'sign_id'        => $this->executeSignId,
                        'patient_id'     => $this->executePatientId,
                        'form_id'        => $oldErrorData['form_id'],
                        'checktime_id'   => implode(',', array_unique($this->generator->usingCheckTime)),
                        'error_type'     => 0,
                        'role'           => 0,
                        'is_process'     => isset($form_group_arr[$oldErrorData['form_id']]) && !empty($form_group_arr[$oldErrorData['form_id']]) && $form_group_arr[$oldErrorData['form_id']] == FormGroup::THROUGH_PROCESS ? 1 : 0,
                        'is_closed'      => 1,
                        'create_user_id' => 0
                    ]);
                }
                $error_checktime_id = $oldErrorData['checktime_id'];
                if(isset($form_group_arr[$oldErrorData['form_id']]) && !empty($form_group_arr[$oldErrorData['form_id']])){
                    if($form_group_arr[$oldErrorData['form_id']] == FormGroup::THROUGH_PROCESS){
                        $error_checktime_id = 0;
                    }
                    if($form_group_arr[$oldErrorData['form_id']] == FormGroup::AE){
                        $error_checktime_id = -1;
                    }
                    if($form_group_arr[$oldErrorData['form_id']] == FormGroup::SAE){
                        $error_checktime_id = -2;
                    }
                }
                $updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']] = [
                    'form_id'=>$oldErrorData['form_id'],
                    'content_arr' => isset($updateTimeFormArr[$error_checktime_id]) && isset($updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]) && isset($updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr']) && !empty($updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr']) ? $updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr'] : []
                ];
                if(!in_array($oldErrorData['error_id'],$check_erroridArr)){
                    if(!in_array($oldErrorData['multi_id'],$updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr'])){
                        $updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr'][] = $oldErrorData['multi_id'];
                    }
                }else{
                    if(!empty($updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr'])){
                        if(isset($form_group_arr[$oldErrorData['form_id']]) && !empty($form_group_arr[$oldErrorData['form_id']]) && $form_group_arr[$oldErrorData['form_id']] == FormGroup::AE){
                            $ae_content_branch_arr = Laminas::$serviceManager->itemPatientAeContent->fetchCol('branch',[
                                'is_del' => 0,
                                'patient_id' => $this->executePatientId,
                                'form_id' => $oldErrorData['form_id'],
                            ]);
                            if(!empty($ae_content_branch_arr)){
                                $relationContentBranch = [];
                                foreach($ae_content_branch_arr as $ae_content_branch){
                                    $relationContentBranch[] = '"'.$ae_content_branch.'"';
                                }
                                $relationContentArr = Laminas::$serviceManager->itemCsaeRelation->fetchCol('content_id', [
                                    'is_del' => 0,
                                    'branch' => StringHelper::toArray($relationContentBranch)
                                ]);
                                $relationContentArr = !empty($relationContentArr) ? array_values(array_unique(array_values($relationContentArr))) : [];
                                $updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr'] = !empty($relationContentArr) ? $relationContentArr : [];
                                unset($relationContentArr);
                                unset($relationContentBranch);
                            }
                            unset($ae_content_branch_arr);
                        }else{
                            $updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr'] = Laminas::$serviceManager->patientFormContent->fetchCol('id',[
                                'is_del' => 0,
                                'patient_id' => $this->executePatientId,
                                'form_id' => $oldErrorData['form_id'],
                                'checktime_id' => $oldErrorData['checktime_id'],
                            ]);
                            $updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr'] = !empty($updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr']) ? array_values($updateTimeFormArr[$error_checktime_id][$oldErrorData['form_id']]['content_arr']) : [];
                        }
                    }
                }
            }
            unset($closed_erroridArr);
        }
        unset($form_group_arr);
        //异步处理访视进度情况信息
        if(!empty($updateTimeFormArr)){
            foreach($updateTimeFormArr as $updateTime=>$updateTimeForms){
                foreach($updateTimeForms as $updateTimeForm){
                    Laminas::$serviceManager->swTaskClient->send([
                        'svName' => 'projectPatientworkbatch',
                        'methodName' => 'multipleUpdateData',
                        'params' => [
                            'item_id'      => $this->generator->itemId,
                            'itemsig_id'   => $this->executeSignId,
                            'patient_id'   => $this->executePatientId,
                            'checktime_id' => $updateTime,
                            'form_id'      => $updateTimeForm['form_id'],
                            'operate_type'=>11,
                            'content_id'=>!empty($updateTimeForm['content_arr']) ? $updateTimeForm['content_arr'] : [],
                            'user_id' => Laminas::$serviceManager->identity->getId()
                        ]
                    ]);
                }
                unset($updateTimeFormArr[$updateTime]);
            }
        }
        unset($updateTimeFormArr);

        unset($oldErrorDatas);
    }

    private function clearError()
    {
        $c = [
            'expression_id' => $this->generator->expressHash,
            'error_type' => 0,
            'is_plugin' => ''
        ];

        if ($this->patientId) {
            $c['patient_id'] = $this->patientId;
        }
        Laminas::$serviceManager->itemPatientFormLogicError->update(['is_del' => 1], $c);

        // 手动质疑
        Laminas::$serviceManager->itemPatientFormLogicError->update(['is_del' => 1], [
            'patient_id' => $this->patientId,
            'expression_id' => 0,
            'is_plugin' => ''
        ]);
    }

    /**
     * 把必填没写的展示出来
     */
    public function usingRequiredPlugin()
    {
        if (!isset($this->pluginContainer['required'])) {
            $this->pluginContainer['required'] = new Required();
        }

        return $this;
    }

    /**
     * 执行!
     */
    public function execute()
    {
        $expression = $this->logicExpression;
        $executeList = $this->getExecuteList();

        foreach ($executeList as $patientId => $item) {
            // 当前正在执行的受试者id
            $this->executePatientId = $patientId;
            self::debugPrint("当前受试者: {$patientId}");

            // 扔到闭包里面去循环, 怕出错了循环断开了
            $callable = function (int $multiId = 0, $multiIndex = 0) use ($patientId, $expression, $item) {
                $this->executeMultiId = $multiId;
                $this->executeMultiIndex = $multiIndex;
                $this->executeSignId = $item['itemsig_id'];
                if ($this->pluginContainer) {
                    foreach ($this->pluginContainer as $plugin) {
                        $plugin->setParams([
                            'patientId' => $this->executePatientId,
                            'signId' => $item['itemsig_id'],
                            'itemId' => $this->itemId,
                            'logicApp' => $this
                        ]);
                        $plugin->execute();
                    }
                }

                try {
                    $isSuccess = false;
                    // TODO: cache
                    $evalCode = $this->getEvalCode($expression);

                    self::debugPrint("evalcode : {$evalCode}");
                    eval($evalCode);
                    if ($isSuccess === true) {  //需要发质疑
                        self::debugPrint('条件成立');
                        $this->executeFailHandler($expression, null);
                    } else { //需要关闭质疑
                        $this->executeSuccessHandler();
                    }
                }catch (NotWriteCheckTimeException | InvalidValException $exception) {
                    self::debugPrint($exception->getMessage());
                } catch (\Throwable $e) {
                    throw new InvalidValException('executeFailHandler Exception' . $e->getMessage());
                }
            };

            $multi = $this->getIsMulti();

            $this->executeMultiId = 0;
            // 一对一
            if ($multi === false) {
                $callable();
            } else {
                //一对多的表单 只处理当前表单的
                if($this->formContentId){
                    $callable($this->formContentId, 1);
                }else{
                    // 一对多
                    foreach (array_values($multi) as $k => $multiId) {
                        $callable($multiId, $k + 1);
                    }
                }

            }
        }
//            return true;
    }

    // 调用的胜哥的方法
    public static function questionUpdate(int $patientId, int $itemId, string $checkTime, $type = 0, int $errorType = 0, int $formId = 0, int $roleType = 0)
    {
        return;
    }

    private function getIsMulti()
    {
        if (!$this->generator->hasMulti) {
            return false;
        }

        if ($this->generator->multiGroupId === FormGroup::AE) {
            $aeRelation = Laminas::$serviceManager->itemCsaeRelation->fetchCol('content_id', [
                'patient_id' => $this->executePatientId,
                'is_del' => 0
            ]);

            $multiData = Laminas::$serviceManager->itemPatientAeContent->fetchCol('id', ['id' => $aeRelation]);
        } else {
            $condition = [
                'patient_id' => $this->executePatientId,
                'form_id' => $this->generator->multiFormId,
                'checktime_id' => $this->generator->multiFormCheckTimeId,
                'is_del' => 0
            ];

            // 贯穿全程不要处理检查点
            if ($this->generator->isProcess === true) {
                unset($condition['checktime_id']);
            }

            $multiData = Laminas::$serviceManager->patientFormContent->fetchCol('id', $condition);
        }

        return $multiData;
    }

    public function reset()
    {
        $this->errors = [];
    }

    public function getErrors(): array
    {
        return $this->errors;
    }


    private function getLogicError($Formid)
    {
        return Laminas::$serviceManager->itemPatientFormLogicError->fetchOne([
            'where' => [
                'patient_id' => $this->executePatientId,
                'item_id' => $this->itemId,
                'expression_id' => $this->generator->expressHash,
                'multi_id' => $this->executeMultiId,
                'form_id' => $Formid,
                'is_del' => 0,
            ]
        ]);
    }

    private function executeFailHandler($expression, $exception = null)
    {
        //需要循环表单存储
        $usingInfos = $this->generator->allusings;
        $expressionNote = "{$this->getExpressionNote()}";
        $content_where = $timeFormFieldArr = $oldError_where = [];
        if(!empty($usingInfos)) {
            foreach ($usingInfos as $usingInfo) {
                $info = explode('_', $usingInfo);
                if (!empty($info)) {
                    $content_where['or'][] = [
                        'checktime_id' => $info[0],
                        'form_id' => $info[1]
                    ];
                    $timeFormFieldArr[$info[0]][$info[1]][] = $info[2];
                    $oldError_where['or'][] = [
                        'checktime_id' => $info[0],
                        'form_id' => $info[1],
                        'prop' => $info[2],
                    ];
                }
            }
        }

        if(!empty($this->formContentId)){
            $patient_content_where = ['id' => $this->formContentId];
        }else{
            if(!empty($content_where)){
                $patient_content_where = [
                    'is_del' => 0,
                    'item_id' => $this->generator->itemId,
                    'patient_id' => $this->executePatientId,
                    $content_where
                ];
            }else{
                $patient_content_where = [new Operator('id',Operator::OP_LT,0)];
            }
            unset($content_where);
        }

        $patient_content_datas = Laminas::$serviceManager->patientFormContent->fetchAll([
            'where'=>$patient_content_where,
            'columns'=>['id','checktime_id','form_id']
        ]);

        $updateTimeFormArr = [];
        if(!empty($patient_content_datas)){
            $poiter_where = [
                'is_del' => 0,
                'item_id' => $this->generator->itemId,
                'error_type' => 0,
                'patient_id' => $this->executePatientId,
                $oldError_where,
            ];
            //获取关闭的未删除的质疑ID
            $closed_errorid = Laminas::$serviceManager->itemPatientFormLogicError->fetchCol('id',$patient_content_where + ['is_closed' => 1]);
            //获取历史已存储的逻辑核查公式质疑信息
            $oldErrorArr = [];
            $oldErrorDatas = Laminas::$serviceManager->itemPatientFormLogicErrorPointer->fetchAll([
                'where'=>$poiter_where,
                'columns'=>['id','error_id','checktime_id','form_id','prop','multi_id']
            ]);
            if(!empty($oldErrorDatas)){
                foreach ($oldErrorDatas as $oldErrorKey=>$oldErrorData){
                    $oldError_key = $oldErrorData['checktime_id'].'_'.$oldErrorData['form_id'].'_'.$oldErrorData['prop'];
                    $oldErrorArr[$oldError_key][$oldErrorData['multi_id']] = $oldErrorData;
                    unset($oldError_key);
                    unset($oldErrorDatas[$oldErrorKey]);
                }
            }
            unset($oldErrorDatas);
            $form_group_arr = Laminas::$serviceManager->itemForm->fetchCol('group_id',[
                'is_del' => 0,
                'item_id' => $this->generator->itemId,
            ]);

            //查询表单类型
            foreach($patient_content_datas as $patient_content_key=>$patient_content_data){
                if(isset($timeFormFieldArr[$patient_content_data['checktime_id']]) && isset($timeFormFieldArr[$patient_content_data['checktime_id']][$patient_content_data['form_id']]) && !empty($timeFormFieldArr[$patient_content_data['checktime_id']][$patient_content_data['form_id']])) {
                    //print_r($timeFormFieldArr[$patient_content_data['checktime_id']][$patient_content_data['form_id']]);die;
                    foreach($timeFormFieldArr[$patient_content_data['checktime_id']][$patient_content_data['form_id']] as $timeFormFied){
                        $error_key = $patient_content_data['checktime_id'].'_'.$patient_content_data['form_id'].'_'.$timeFormFied;
                        $errorPointer = isset($oldErrorArr[$error_key]) && isset($oldErrorArr[$error_key][$patient_content_data['id']]) && !empty($oldErrorArr[$error_key][$patient_content_data['id']]) ? $oldErrorArr[$error_key][$patient_content_data['id']] : [];
                        $errorId = !empty($errorPointer) ? $errorPointer['error_id'] : 0;
                        $pointer_id = !empty($errorPointer) ? $errorPointer['id'] : 0;
                        if (!empty($errorId)) {
                            //质疑是否已经关闭  如果质疑已经关闭 并且数据已经更改 就重新发质疑 ，不改这部分字段就不发质疑   $timeFormFied是发质疑的字段 需判断有没有修改
                            if(in_array($errorId,$closed_errorid)){
                                //发质疑字段数据有修改 则重新发 $timeFormFied
                               if(isset($this->note_arr) && !empty($this->note_arr) && in_array($timeFormFied,$this->note_arr)){
                                    //字段有修改 需要重新发质疑
                                   $errorId = Laminas::$serviceManager->itemPatientFormLogicError->save([
                                       'patient_id' => $this->executePatientId,
                                       'item_id' => $this->generator->itemId,
                                       'error_expression' => $this->getExpressionNote(), //$this->generator->originExpression,
                                       'expression_id' => $this->generator->expressHash,
                                       'is_exception' => $exception instanceof \Throwable ? 1 : 0,
                                       'expression_note' => $exception instanceof \Throwable ? '核查脚本运行失败。' : $expressionNote,
                                       'is_del' => 0,
                                       'multi_id' => $patient_content_data['id'],
                                       'sign_id' => $this->executeSignId,
                                       'is_queried' => 1,
                                       'checktime_id' => $patient_content_data['checktime_id'],
                                       'error_type' => 0,
                                       'is_closed' => 0,
                                       'form_id' => $patient_content_data['form_id'],
                                       'role' => 0,
                                       'create_user_id' => 0,
                                   ]);
                                   //log表增加记录
                                   Laminas::$serviceManager->itemPatientFormLogicErrorLog->save([
                                       'error_id' => $errorId,
                                       'is_error' => 0,
                                       'item_id' => $this->generator->itemId,
                                       'sign_id' => $this->executeSignId,
                                       'patient_id' => $this->executePatientId,
                                       'form_id' =>$patient_content_data['form_id'],
                                       'checktime_id' => $patient_content_data['checktime_id'],
                                       'error_type' => 0,
                                       'role' => 0,
                                       'create_user_id' => 0,
                                       'is_process' => isset($form_group_arr[$patient_content_data['form_id']]) && !empty($form_group_arr[$patient_content_data['form_id']]) && $form_group_arr[$patient_content_data['form_id']] == FormGroup::THROUGH_PROCESS ? 1 : 0
                                   ]);

                                   //poiter表增加信息
                                   Laminas::$serviceManager->itemPatientFormLogicErrorPointer->save([
                                       'patient_id' => $this->executePatientId,
                                       'checktime_id' => $patient_content_data['checktime_id'],
                                       'form_id' => $patient_content_data['form_id'],
                                       'item_id' => $this->generator->itemId,
                                       'is_del' => 0,
                                       'multi_id' =>  $patient_content_data['id'],
                                       'logic_expression_id' => $this->generator->expressHash,
                                       'error_id' => $errorId,
                                       'prop' =>$timeFormFied,
                                       'error_message' => $this->generator->note,
                                       'error_type' => 0,
                                       'create_user_id' => 0
                                   ]);
                                   // 直接发送到sdm
                                   Laminas::$serviceManager->itemPatientFormLogicErrorQuery->save([
                                       'content' => $this->getExpressionNote(),
                                       'error_id' => $errorId,
                                       'platform' => Laminas::$serviceManager->itemPatientFormLogicErrorQuery::PLATFORM_EDC,
                                       'is_reply' => 0,
                                       'create_user_id' => 0
                                   ]);
                               }
                            }else{
                                //未关闭状态 但数据有修改 需要把原来的质疑关闭并重新发质疑
                                if(isset($this->note_arr) && !empty($this->note_arr) && in_array($timeFormFied,$this->note_arr)){
                                    //有修改 需要重新发质疑 无修改不动
                                    Laminas::$serviceManager->itemPatientFormLogicError->update(['is_closed' => 1, 'update_user_id' => 0], ['id' => $errorId]);
                                    //插入关闭质疑的沟通记录
                                    // SDMHelper::app()->logic->setQuery('关闭质疑', $oldErrorData['error_id'], $this->itemId);
                                    Laminas::$serviceManager->itemPatientFormLogicErrorQuery->save([
                                        'content'        => '关闭质疑',
                                        'error_id'       => $errorId,
                                        'platform'       => 1,
                                        'is_reply'       => 1,
                                        'pointer_id'     => $pointer_id,
                                        'item_id'        => $this->itemId,
                                        'create_user_id' => 0 // 系统
                                    ]);
                                    //log表增加关闭记录
                                    Laminas::$serviceManager->itemPatientFormLogicErrorLog->save([
                                        'error_id'       => $errorId,
                                        'is_error'       => 0,
                                        'item_id'        => $this->generator->itemId,
                                        'sign_id'        => $this->executeSignId,
                                        'patient_id'     => $this->executePatientId,
                                        'form_id'        => $patient_content_data['form_id'],
                                        'checktime_id'   => implode(',', array_unique($this->generator->usingCheckTime)),
                                        'error_type'     => 0,
                                        'role'           => 0,
                                        'is_process'     => isset($form_group_arr[$patient_content_data['form_id']]) && !empty($form_group_arr[$patient_content_data['form_id']]) && $form_group_arr[$patient_content_data['form_id']] == FormGroup::THROUGH_PROCESS ? 1 : 0,
                                        'is_closed'      => 1,
                                        'create_user_id' => 0
                                    ]);

                                    $new_errorId = Laminas::$serviceManager->itemPatientFormLogicError->save([
                                        'patient_id'       => $this->executePatientId,
                                        'item_id'          => $this->generator->itemId,
                                        'error_expression' => $this->getExpressionNote(), //$this->generator->originExpression,
                                        'expression_id'    => $this->generator->expressHash,
                                        'is_exception'     => $exception instanceof \Throwable ? 1 : 0,
                                        'expression_note'  => $exception instanceof \Throwable ? '核查脚本运行失败。' : $expressionNote,
                                        'is_del'           => 0,
                                        'multi_id'         => $patient_content_data['id'],
                                        'sign_id'          => $this->executeSignId,
                                        'is_queried'       => 1,
                                        'checktime_id'     => $patient_content_data['checktime_id'],
                                        'error_type'       => 0,
                                        'is_closed'        => 0,
                                        'form_id'          => $patient_content_data['form_id'],
                                        'role'             => 0,
                                        'create_user_id'   => 0,
                                    ]);
                                    //log表增加记录
                                    Laminas::$serviceManager->itemPatientFormLogicErrorLog->save([
                                        'error_id'       => $new_errorId,
                                        'is_error'       => 0,
                                        'item_id'        => $this->generator->itemId,
                                        'sign_id'        => $this->executeSignId,
                                        'patient_id'     => $this->executePatientId,
                                        'form_id'        => $patient_content_data['form_id'],
                                        'checktime_id'   => $patient_content_data['checktime_id'],
                                        'error_type'     => 0,
                                        'role'           => 0,
                                        'create_user_id' => 0,
                                        'is_process'     => isset($form_group_arr[$patient_content_data['form_id']]) && !empty($form_group_arr[$patient_content_data['form_id']]) && $form_group_arr[$patient_content_data['form_id']] == FormGroup::THROUGH_PROCESS ? 1 : 0
                                    ]);

                                    //poiter表增加信息
                                    Laminas::$serviceManager->itemPatientFormLogicErrorPointer->save([
                                        'patient_id'          => $this->executePatientId,
                                        'checktime_id'        => $patient_content_data['checktime_id'],
                                        'form_id'             => $patient_content_data['form_id'],
                                        'item_id'             => $this->generator->itemId,
                                        'is_del'              => 0,
                                        'multi_id'            => $patient_content_data['id'],
                                        'logic_expression_id' => $this->generator->expressHash,
                                        'error_id'            => $new_errorId,
                                        'prop'                => $timeFormFied,
                                        'error_message'       => $this->generator->note,
                                        'error_type'          => 0,
                                        'create_user_id'      => 0
                                    ]);
                                    // 直接发送到sdm
                                    Laminas::$serviceManager->itemPatientFormLogicErrorQuery->save([
                                        'content'        => $this->getExpressionNote(),
                                        'error_id'       => $new_errorId,
                                        'platform'       => Laminas::$serviceManager->itemPatientFormLogicErrorQuery::PLATFORM_EDC,
                                        'is_reply'       => 0,
                                        'create_user_id' => 0
                                    ]);
                                }
                            }
                        } else {
                            $errorId = Laminas::$serviceManager->itemPatientFormLogicError->save([
                                'patient_id' => $this->executePatientId,
                                'item_id' => $this->generator->itemId,
                                'error_expression' => $this->getExpressionNote(), //$this->generator->originExpression,
                                'expression_id' => $this->generator->expressHash,
                                'is_exception' => $exception instanceof \Throwable ? 1 : 0,
                                'expression_note' => $exception instanceof \Throwable ? '核查脚本运行失败。' : $expressionNote,
                                'is_del' => 0,
                                'multi_id' => $patient_content_data['id'],
                                'sign_id' => $this->executeSignId,
                                'is_queried' => 1,
                                'checktime_id' => $patient_content_data['checktime_id'],
                                'error_type' => 0,
                                'is_closed' => 0,
                                'form_id' => $patient_content_data['form_id'],
                                'role' => 0,
                                'create_user_id' => 0,
                            ]);
                            //log表增加记录
                            Laminas::$serviceManager->itemPatientFormLogicErrorLog->save([
                                'error_id' => $errorId,
                                'is_error' => 0,
                                'item_id' => $this->generator->itemId,
                                'sign_id' => $this->executeSignId,
                                'patient_id' => $this->executePatientId,
                                'form_id' =>$patient_content_data['form_id'],
                                'checktime_id' => $patient_content_data['checktime_id'],
                                'error_type' => 0,
                                'role' => 0,
                                'create_user_id' => 0,
                                'is_process' => isset($form_group_arr[$patient_content_data['form_id']]) && !empty($form_group_arr[$patient_content_data['form_id']]) && $form_group_arr[$patient_content_data['form_id']] == FormGroup::THROUGH_PROCESS ? 1 : 0
                            ]);

                            //poiter表增加信息
                            Laminas::$serviceManager->itemPatientFormLogicErrorPointer->save([
                                'patient_id' => $this->executePatientId,
                                'checktime_id' => $patient_content_data['checktime_id'],
                                'form_id' => $patient_content_data['form_id'],
                                'item_id' => $this->generator->itemId,
                                'is_del' => 0,
                                'multi_id' =>  $patient_content_data['id'],
                                'logic_expression_id' => $this->generator->expressHash,
                                'error_id' => $errorId,
                                'prop' =>$timeFormFied,
                                'error_message' => $this->generator->note,
                                'error_type' => 0,
                                'create_user_id' => 0
                            ]);
                            // 直接发送到sdm
                            Laminas::$serviceManager->itemPatientFormLogicErrorQuery->save([
                                'content' => $this->getExpressionNote(),
                                'error_id' => $errorId,
                                'platform' => Laminas::$serviceManager->itemPatientFormLogicErrorQuery::PLATFORM_EDC,
                                'is_reply' => 0,
                                'create_user_id' => 0
                            ]);
                        }

                        unset($error_key);
                        unset($errorPointer);
                        unset($errorId);
                    }
                }
                $error_checktime_id = $patient_content_data['checktime_id'];
                if(isset($form_group_arr[$patient_content_data['form_id']]) && !empty($form_group_arr[$patient_content_data['form_id']])){
                    if($form_group_arr[$patient_content_data['form_id']] == FormGroup::THROUGH_PROCESS){
                        $error_checktime_id = 0;
                    }
                    if($form_group_arr[$patient_content_data['form_id']] == FormGroup::AE){
                        $error_checktime_id = -1;
                    }
                    if($form_group_arr[$patient_content_data['form_id']] == FormGroup::SAE){
                        $error_checktime_id = -2;
                    }
                }
                $updateTimeFormArr[$error_checktime_id][$patient_content_data['form_id']] = [
                    'form_id'=>$patient_content_data['form_id'],
                    'content_arr' => isset($updateTimeFormArr[$error_checktime_id]) && isset($updateTimeFormArr[$error_checktime_id][$patient_content_data['form_id']]) && isset($updateTimeFormArr[$error_checktime_id][$patient_content_data['form_id']]['content_arr']) && !empty($updateTimeFormArr[$error_checktime_id][$patient_content_data['form_id']]['content_arr']) ? $updateTimeFormArr[$error_checktime_id][$patient_content_data['form_id']]['content_arr'] : []
                ];
                $updateTimeFormArr[$error_checktime_id][$patient_content_data['form_id']]['content_arr'][] = $patient_content_data['id'];
                unset($patient_content_datas[$patient_content_key]);
            }

            unset($formtype_arr);
            unset($through_form_arr);
            unset($oldErrorArr);
        }
        unset($oldError_where);
        unset($timeFormFiedlArr);
        unset($patient_content_datas);

        //异步处理访视进度情况信息
        if(!empty($updateTimeFormArr)){
            foreach($updateTimeFormArr as $updateTime=>$updateTimeForms){
                foreach($updateTimeForms as $updateTimeForm){
                    Laminas::$serviceManager->swTaskClient->send([
                        'svName' => 'projectPatientworkbatch',
                        'methodName' => 'multipleUpdateData',
                        'params' => [
                            'item_id'      => $this->generator->itemId,
                            'itemsig_id'   => $this->executeSignId,
                            'patient_id'   => $this->executePatientId,
                            'checktime_id' => $updateTime,
                            'form_id'      => $updateTimeForm['form_id'],
                            'operate_type'=>11,
                            'content_id'=>!empty($updateTimeForm['content_arr']) ? $updateTimeForm['content_arr'] : [],
                            'user_id' => Laminas::$serviceManager->identity->getId()
                        ]
                    ]);
                }
                unset($updateTimeFormArr[$updateTime]);
            }
        }
        unset($updateTimeFormArr);


//        $this->setProcess();

        // TODO redis存当前检查点所有表单的处理结果
       // $this->cachedLogicError();
    }


    public function setError(array $params)
    {
        if (!$params['id']) {
            throw new InvalidArgumentException('未填写过的表单无法质疑。');
        }
        $this->executePatientId = $params['patient_id'];
        $this->executeFormId = $params['form_id'];
        $this->executeCheckTimeId = $params['checktime_id'];
        $this->executeMultiId = $params['id'] ?: 0;
        $this->setItemId($params['item_id']);
        $errorId = Laminas::$serviceManager->itemPatientFormLogicError->save([
            'patient_id' => $this->executePatientId,
            'item_id' => $this->itemId,
            'error_expression' => '', // 人工质疑没有公式
            'expression_id' => 0,
            'is_exception' => 0,
            'expression_note' => $params['content'],
            'is_del' => 0,
            'multi_id' => $this->executeMultiId,
            'sign_id' => $params['itemsig_id'],
            'is_queried' => 1,
            'checktime_id' => $this->executeCheckTimeId,
            'error_type' => 1,
            'form_id' => $this->executeFormId,
            'role' => $params['confirm_type']
        ]);

        Laminas::$serviceManager->itemPatientFormLogicError->update([
            'expression_id' => $errorId,
        ], ['id' => $errorId]);


        // 直接发送到sdm
        Laminas::$serviceManager->itemPatientFormLogicErrorQuery->save([
            'content' => $params['content'],
            'error_id' => $errorId,
            'platform' => Laminas::$serviceManager->itemPatientFormLogicErrorQuery::PLATFORM_EDC,
            'is_reply' => 0
        ]);

        $this->setCustomPointer($errorId);
    }


    private function setPointer($errorId,$info)
    {
        $has = Laminas::$serviceManager->itemPatientFormLogicErrorPointer->fetchOne([
            'where' => [
                'patient_id' => $this->executePatientId,
                'checktime_id' => $info[0],
                'form_id' => $info[1],
                'multi_id' => $this->ContentId,
                'logic_expression_id' => $this->generator->expressHash,
                'prop' => $info[2],
                'error_id' => $errorId,
                'create_user_id' => 0
            ]
        ]);
        if (!isset($has['id'])) {
            Laminas::$serviceManager->itemPatientFormLogicErrorPointer->save([
                'patient_id' => $this->executePatientId,
                'checktime_id' => $info[0],
                'form_id' => $info[1],
                'item_id' => $this->itemId,
                'is_del' => 0,
                'multi_id' => $this->ContentId,
                'logic_expression_id' => $this->generator->expressHash,
                'error_id' => $errorId,
                'prop' => $info[2],
                'error_message' => $this->generator->note,
                'error_type' => 0,
                'create_user_id' => 0
            ]);
        } else {
            $s = Laminas::$serviceManager->itemPatientFormLogicErrorPointer->update(['is_del' => 0], ['id' => $has['id']]);
        }
    }


    private function setCustomPointer($errorId)
    {
        $has = Laminas::$serviceManager->itemPatientFormLogicErrorPointer->fetchOne([
            'where' => [
                'patient_id' => $this->executePatientId,
                'checktime_id' => $this->executeCheckTimeId,
                'form_id' => $this->executeFormId,
                'prop' => $_POST['prop'],
                'error_id' => $errorId,
                'multi_id' => $this->executeMultiId
            ]
        ]);

        if (!isset($has['id'])) {
            Laminas::$serviceManager->itemPatientFormLogicErrorPointer->save([
                'patient_id' => $this->executePatientId,
                'checktime_id' => $this->executeCheckTimeId,
                'form_id' => $this->executeFormId,
                'item_id' => $this->itemId,
                'is_del' => 0,
                'logic_expression_id' => '',
                'error_id' => $errorId,
                'prop' => $_POST['prop'],
                'error_message' => $_POST['content'],
                'multi_id' => $this->executeMultiId,
                'error_type' => 1
            ]);
        } else {
            Laminas::$serviceManager->itemPatientFormLogicErrorPointer->update(['is_del' => 0], ['id' => $has['id']]);
        }

        self::questionUpdate(
            $this->executePatientId,
            $this->itemId,
            $this->executeCheckTimeId,
            0,
            1,
            $this->executeFormId,
            0 // 1就是0 2就是1
        );
    }

    private function getExpressionNote(): string
    {
        return $this->generator->note;
    }

    private function cachedLogicError()
    {
//        Laminas::$serviceManager->redisExtend->getRedisInstance()->set("logic:{$this->itemId}:{$this->executePatientId}:{$this->checkTimeId}", json_encode());
    }

    public function validExpression($expression)
    {
        $this->validVars($expression);
    }

    /**
     * 验证表达式变量是否合法
     *  # 当前规则:
     *  - 必须配置一个变量
     *  - 必须填写合法的变量名(表单配置了这个变量名, 不能瞎写)
     * @param $expression
     */
    private function validVars($expression): void
    {
        return ;
        $pattern = self::formatPattern();
        preg_match_all($pattern, $expression, $vars);
        $vars = array_unique(current($vars));
        if (!$vars) {
//            throw new InvalidLogicExpressionException('逻辑核查公式必须配置变量。');
        }

        foreach ($vars as $var) {
            $varString = str_replace([self::VAR_MARKS_LEFT, self::VAR_MARKS_RIGHT], '', $var);
            if (stripos($varString, '.') !== false) {
                list($checkTime, $varString) = explode('.', $varString);
            }

            if (!Laminas::$serviceManager->itemFormField->fetchOne(['where' => ['var_name' => $varString, 'item_id' => $this->itemId]])) {
                throw new InvalidLogicExpressionException("变量 {$var} 不是一个合法的变量。");
            }
        }
    }
}