<?php

namespace Application\Service\Extension\Helper;

use Application\Common\DictionaryVarNameEnum;
use Application\Common\Enum;
use Application\Service\DB\Collect\Category;
use Application\Service\DB\Dictionary\Form;
use Application\Service\DB\Dictionary\FormField;
use Application\Service\DB\Dictionary\FormGroup;
use Application\Service\Exceptions\InvalidArgumentException;
use Application\Service\Extension\Helper\base\BaseHelper;
use Application\Service\Extension\Laminas;
use Application\Service\Extension\Uploader\adapter\Oss;
use Exception;

/**
 * @property FieldHelper $field //TODO delete
 * @method getShareFormGroup(int $formId = null) 等同于getGcoGroupForm。原来函数名起的不太合理
 */
class FormHelper extends BaseHelper
{
    /**
     * 表单id
     * @var int|array|mixed|null
     */
    protected ?int $formId = null;

    /**
     * 是否是字典项
     * @var bool
     */
    protected bool $isDictionary = false;

    private const HELPER_KEY_FROM_VERSION = 'FORM_VERSION';

    private const HELPER_KEY_AE_FORM = 'AE_FORM';

    private const HELPER_KEY_GCO_POOL = 'GCO_POOL';

    public function __construct($config = [])
    {
        if (is_array($config)) {
            parent::__construct($config);
            $this->attributes = $config;
        } else {
            $this->formId = $config;
        }
    }

    public static array $container = [];

    private array $components = [
        'field' => FieldHelper::class,
    ];

    public function __get($name)
    {
        /** @var BaseHelper $class */
        return (new $this->components[$name]($this->attributes));// new FormHelper($params);

    }

    /**
     * 表单日期公共部分
     */
    public const COMMON_DATE_OPTIONS = [
        [
            'type' => 'Radio',
            'label' => '是否为基点',
            'prop' => 'is_anchor',
            'default' => '0',
            'radios' => [
                ['label' => '否', 'value' => '0'],
                ['label' => '是', 'value' => '1'],
            ],
            'rules' => [
                [
                    'required' => true,
                    'message' => '请输入是否为基点',
                ]
            ],
        ],
        [
            'type' => 'Radio',
            'label' => '访视日期',
            'prop' => 'is_booked_time',
            'default' => '0',
            'radios' => [
                ['label' => '否', 'value' => '0'],
                ['label' => '是', 'value' => '1'],
            ],
            'rules' => [
                [
                    'required' => true,
                    'message' => '请输入是否为访视日期',
                ]
            ],
        ],[
            'type' => 'Radio',
            'label' => '超窗判断',
            'prop' => 'is_hyperwindow',
            'default' => '0',
            'radios' => [
                ['label' => '否', 'value' => '0'],
                ['label' => '是', 'value' => '1'],
            ],
            'rules' => [
                [
                    'required' => true,
                    'message' => '请输入是否为超窗判断',
                ]
            ],
        ]
    ];

    public const COMMON_ADVANCE_OPTIONS = [
        'required' => [
            'type' => 'Switch1',
            'label' => '是必填项',
            'prop' => 'validator[v-required]',
        ],
        'mobile' => [
            'type' => 'Switch1',
            'label' => '手机号格式',
            'prop' => 'validator[v-mobile]',
        ],
        'email' => [
            'type' => 'Switch1',
            'label' => '邮箱格式',
            'prop' => 'validator[v-email]',
        ],
        'date' => [
            'type' => 'Switch1',
            'label' => '是日期',
            'prop' => 'validator[v-isDate]',
        ],
        'max_length' => [
            'type' => 'Input',
            'label' => '最大长度',
            'prop' => 'validator[v-maxLength]',
        ],
        'min_length' => [
            'type' => 'Input',
            'label' => '最小长度',
            'prop' => 'validator[v-minLength]',
        ],
        'min' => [
            'type' => 'Input',
            'label' => '最小值',
            'prop' => 'validator[v-minValue]',
        ],
        'max' => [
            'type' => 'Input',
            'label' => '最大值',
            'prop' => 'validator[v-maxValue]',
        ],
        'uppercase' => [
            'type' => 'Switch1',
            'label' => '最大值',
            'prop' => 'validator[v-uppercase]',
        ],
        'text_count' => [
            'type' => 'Input',
            'label' => '输入文本字数',
            'prop' => 'validator[v-textCount]',
        ],
    ];

    /**
     * 设置当前是否为字典项
     * @param bool $isDictionary
     * @return $this
     */
    public function setIsDictionary(bool $isDictionary): FormHelper
    {
        $this->isDictionary = $isDictionary;
        return $this;
    }

    /**
     * 获取所有表单类型并排序
     * @return array
     */
    public static function getGroupIdOptions(): array
    {
        return Laminas::$serviceManager->dictionaryFormGroup->fetchAll([
            'columns' => [
                'name as label', 'id as value', 'order'
            ],
            'order' => ['order ASC'],
        ]);
    }

    /**
     * 获取所有检查项表单
     * 嗯，可以让选项目已经设置的检查项分类，比较好
     * @return mixed
     */
    public static function getChecklistIdOptions()
    {
        $itemId = $_POST['item_id'];

        $default = [['label' => '否', 'value' => '0']];

        $checkNameData = Laminas::$serviceManager->itemCheckname->fetchAll([
            'columns' => ['category_id'],
            'group' => ['category_id'],
            'where' => ['is_del' => 0, 'item_id' => $itemId]
        ]);
        unset($checkname_where);
        if (!$checkNameData) {
            return $default;
        }

        $template = ArrayHelper::getColumn($checkNameData, 'category_id');

        $query = Laminas::$serviceManager->dictionaryCheckcategory->fetchAll([
            'columns' => ['category_name as label', 'id as value','is_form'],
            'where' => ['is_del' => 0, 'id' => $template]
        ]);
        if(!empty($query)){
            foreach($query as &$queryInfo){
                if($queryInfo['is_form'] == 1){
                    $queryInfo['label'] .= '【常规识别】';
                }
                unset($queryInfo['is_form']);
            }
        }

        return ArrayHelper::merge($default, $query);
    }

    private static function getRules(int $type): array
    {
        $rules = [];

        if ($type == FormField::FORM_FIELD_TYPE_INTEGER) { // 整数
            $preg = trim(ValidatorHelper::PREG_IS_INTEGER, '/');
            $rules[] = ['required' => false, 'trigger' => 'blur', 'message' => '请填写正确的整数值', 'pattern' => $preg];
        } elseif ($type == FormField::FORM_FIELD_TYPE_FLOAT_1) {
            $keep = 1;
            $preg = trim("/^[-+]?[0-9]*([\.][0-9]{1,$keep})?$/", '/');
            $rules[] = ['required' => false, 'trigger' => 'blur', 'message' => '请填写不能超过一位小数的数值', 'pattern' => $preg];
        } elseif ($type == FormField::FORM_FIELD_TYPE_FLOAT_2) {
            $keep = 2;
            $preg = trim("/^[-+]?[0-9]*([\.][0-9]{1,$keep})?$/", '/');
            $rules[] = ['required' => false, 'trigger' => 'blur', 'message' => '请填写不能超过两位小数的数值', 'pattern' => $preg];
        } elseif ($type == FormField::FORM_FIELD_TYPE_FLOAT_3) {
            $keep = 3;
            $preg = trim("/^[-+]?[0-9]*([\.][0-9]{1,$keep})?$/", '/');
            $rules[] = ['required' => false, 'trigger' => 'blur', 'message' => '请填写不能超过三位小数的数值', 'pattern' => $preg];
        }

        return $rules;
    }

    /**
     * 返回日期选项
     * @return array[]
     */
    public static function getTextOptions($textType): array
    {
        $rules = self::getRules($textType);
        return [
            [
                'type' => 'Input',
                'label' => '默认值',
                'placeholder' => '请输入默认值',
                'prop' => 'default' . $textType,
                'rules' => $rules,
            ],
            [
                'type' => 'Input',
                'label' => '单位',
                'placeholder' => '请输入单位',
                'prop' => 'unit',
                'default' => '',
                'rules' => [
                    ['required' => false]
                ],
            ]
        ];
    }

    /**
     * 获取高级选项设置
     */
    public static function getAdvanceOptions($type): array
    {
        $rulesId = ArrayHelper::getColumn(Laminas::$serviceManager->dictionaryFormtyperule->fetchAll([
            'columns' => ['rule_id'],
            'where' => ['formtype_id' => $type, 'is_del' => 0]
        ]) ?: [], 'rule_id');

        if (!$rulesId) {
            return [];
        }


        $rules = ArrayHelper::index(Laminas::$serviceManager->dictionaryRule->fetchAll([
            'columns' => ['rule_code', 'show_name'],
            'where' => ['id' => $rulesId, 'is_del' => 0]
        ]) ?: [], 'rule_code');

        $formData = [];

        foreach ($rules as $ruleCode => $rule) {
            $data = self::COMMON_ADVANCE_OPTIONS[$ruleCode];
            if ($data) {
                $data['label'] = $rule['show_name'] ?: $data['label'];
                $data['rules'] = self::getRules($type);
                $formData[] = $data;
            }
        }
        return $formData;
    }

    /**
     * 返回日期选项
     * @return array[]
     */
    public static function getDateOptions(int $dateType): array
    {
        $getDateType = function ($dateType) {
            switch ($dateType) {
                case Enum::FORM_FIELD_TYPE_DATE_UK:
                    return 'Uk';
                case FormField::FORM_FIELD_TYPE_DATE_SECOND:
                    return 'DateTimeSecond';
                case Enum::FORM_FIELD_TYPE_DATE:
                    return 'Date';
                case Enum::FORM_FIELD_TYPE_DATETIME:
                    return 'DateTime';
                default:
                    throw new InvalidArgumentException("错误的类型~");
            }
        };
        return ArrayHelper::merge(self::COMMON_DATE_OPTIONS, [
                [
                    'type' => $getDateType($dateType),
                    'label' => '默认值',
                    'placeholder' => '无默认值会默认当前时间',
                    'prop' => 'default' . $dateType,
                    'rules' => [
                        ['required' => false, 'trigger' => 'blur']
                    ],
                ]
        ]);
    }



    /**
     * Notes: 单选 多选 下拉的显示表单类型 其余情况不显示
     * @param
     * @return
     * @author haojinhua
     * @date 2025-02-11
     */
    public static function getSelectOptions(int $type): array
    {
        return [
            [
                'type' => 'Select',
                'label' => '选项字典',
                'placeholder' => '选项字典',
                'options' => Laminas::$serviceManager->dictionaryLeverform->fetchAll([
                    'where'=>"is_del = 0",
                    'columns'=>['value'=>'id','label'=>'form_name'],
                    'order'=>'form_order asc'
                ]),
                'prop' => 'dicform_id',
                'rules' => [
                    ['required' => false, 'message' => '请选择选项字典', 'trigger' => 'blur']
                ]
            ],
        ];
    }

    public static function getItemFormSourceOptions(int $item_id): array
    {
        return [
            [
                'type' => 'ItemFormSourceSet',
                'label' => '数据来源设置',
                'placeholder' => '数据来源设置',
                'prop' => 'item_form_source_set',
                'params' => [
                    'item_id' => $item_id,
                ],
                'rules' => [
                    ['required' => true, 'message' => '请设置数据来源', 'trigger' => 'blur']
                ]
            ],
        ];
    }

    /**
     * 获取关联信息
     * @param string $source
     * @return string[][]
     */
    public static function getRelationInformationOptions(string $source = 'dictionaryFormVersion'): array
    {
        $params = Laminas::$app->getMvcEvent()->getRequest();

        $query = Laminas::$serviceManager->{$source}->getField([
            'form_id' => $params->getPost('form_id'),
            'version' => 'v1.0'
        ], true);

        $options = [['label' => '无关联信息', 'value' => '0']];

        $id = Laminas::$app->getMvcEvent()->getRequest()->getPost('id');

        foreach ($query as $v) {
            if ($id) {
                // 编辑单选选项
                if ($params->getPost('form_type') == FormField::FORM_CONFIG_RADIO) {
                    // 排除自身选项
                    if (isset($v['children']) && isset($v['children'][$id]) || self::hasRelation($v['children'])) {
                        continue;
                    }
                }
            }

            $options[] = ['label' => $v['name'], 'value' => $v['id']];
        }

        return $options;
    }

    private static function hasRelation($children): bool
    {
        foreach ($children as $v) {
            if ($v['relation_information'] != [0]) {
                return true;
            }
        }

        return false;
    }

    /**
     * 处理关联表单信息
     * 排除掉空选项(没有关联信息)
     * @param string $relationInformation
     * @param $relationMap
     * @return string
     */
    public static function handleRelationInformation(string $relationInformation, $relationMap): string
    {
        if (stripos($relationInformation, ',') !== false) {
            $relationInformation = explode(',', $relationInformation);
        }

        if (is_string($relationInformation)) {
            $relationInformation = $relationMap[$relationInformation] ?? '0';
        } elseif (is_array($relationInformation)) {
            foreach ($relationInformation as &$value) {
                if ($value) {
                    $value = $relationMap[$value];
                }
            }
        }

        if (is_array($relationInformation)) {
            $relationInformation = implode(',', $relationInformation);
        }

        return $relationInformation;
    }

    /**
     * 获取表单计算公式计算符和变量
     * @param array $data
     * @param false $initialize
     * @return array|mixed
     */
    public static function getCalculateCondition($data = [], $initialize = false)
    {
        if (!$initialize) {
            $condition[] = ['label' => '表单计算结果', 'var' => 'RESULT', 'is_condition' => false];
            $condition[] = ['label' => '乘号', 'var' => '*', 'is_condition' => true];
            $condition[] = ['label' => '加号', 'var' => '+', 'is_condition' => true];
            $condition[] = ['label' => '减号', 'var' => '-', 'is_condition' => true];
            $condition[] = ['label' => '除号', 'var' => '/', 'is_condition' => true];
            $condition[] = ['label' => '左括号', 'var' => '(', 'is_condition' => true];
            $condition[] = ['label' => '右括号', 'var' => ')', 'is_condition' => true];
            $condition[] = ['label' => '等于', 'var' => '=/==  （示例 A=IF(B==1,C,D)）', 'is_condition' => true];
            $condition[] = ['label' => '不等于', 'var' => '!=', 'is_condition' => true];
            $condition[] = ['label' => '小于', 'var' => '<', 'is_condition' => true];
            $condition[] = ['label' => '大于', 'var' => '>', 'is_condition' => true];
            $condition[] = ['label' => '小于等于', 'var' => '<=', 'is_condition' => true];
            $condition[] = ['label' => '大于等于', 'var' => '>=', 'is_condition' => true];
            $condition[] = ['label' => '对浮点数进行四舍五入', 'var' => 'ROUND(要处理的值, 可选的十进制小数点后数字的数目。)', 'is_condition' => true];
            $condition[] = ['label' => '保留小数点后几位', 'var' => 'ROUNDTO(要处理的值, 可选的十进制小数点后数字的数目。)', 'is_condition' => true];
            $condition[] = ['label' => '舍去小数部分取整', 'var' => 'FLOOR(要处理的值)', 'is_condition' => true];
            $condition[] = ['label' => '自然对数', 'var' => 'LN(要计算对数的值)', 'is_condition' => true];
            $condition[] = ['label' => '计算两个日期之间的天数、月数或年数', 'var' => 'DATEDIF(开始日期, 结束日期, "单位")', 'is_condition' => true];
            $condition[] = ['label' => 'AND', 'var' => 'AND(...条件)', 'is_condition' => true];
            $condition[] = ['label' => '如果', 'var' => 'IF(条件, 成立结果, 不成立结果)', 'is_condition' => true];
            $condition[] = ['label' => 'OR', 'var' => 'OR(...条件)', 'is_condition' => true];
        }

        $versionData = $data;
        if (!$data) {
            $versionData = Laminas::$serviceManager->itemFormVersion->getField(['form_id' => $_POST['id'] ?? 0]);
        }

        foreach ($versionData as $datum) {
            if ($datum['var_name']) {
                $condition[] = ['label' => $datum['name'], 'var' => $datum['var_name'], 'is_condition' => false];
            }

            if (isset($datum['children'])) {
                $condition = ArrayHelper::merge($condition, self::getCalculateCondition($datum['children'], true));
            }
        }

        return $condition;
    }

    public static function getCalculateConditionWithClass(): array
    {
        $constant = self::getCalculateCondition();

        // 表单变量 //计算符号
        $constVar = $condition = [];

        foreach ($constant as $item) {
            if ($item['is_condition'] === false) {
                $constVar[] = $item['var'];
            } else {
                $condition[] = $item['var'];
            }
        }

        return [$constVar, $condition];
    }

    /**
     * 获取处理后的表达式结果
     * @param $expression
     * @param string $mode
     * @return array|string
     */
    public static function getFormatFormExpression($expression, string $mode = '')
    {
        if (!$expression) {
            return '';
        }

        preg_match("/(.*?)=(.*)/", $expression, $match);

        if (!$match || count($match) != 3) {
            return '';
        }

        $var = explode(' ', trim($match[2]));

        // 预览的话, 前端不允许有重复的变量名和数字类型的值
        if ($mode == 'preview') {
            foreach ($var as $k => $item) {
                if (is_numeric($item)) {
                    unset($var[$k]);
                }
            }

            $var = array_unique($var);
        }

        return [
            'result' => trim($match[1]),
            'expression' => $var
        ];
    }

    /**
     * @note 获取随机表单的系统随机字段id
     * @return int
     * @throws Exception
     */
    public static function getSystemRandomFieldId() : int
    {
        $result = 0;
        if(SDMHelper::app()->form->getGroupId($_POST['form_id']) == FormGroup::RANDOM_GROUP) {
            // 验证随机字段是否是系统随机类型
            $formFields = SDMHelper::app()->form->getVersionData();
            foreach ($formFields as &$formField) {
                if(in_array($formField['var_name'], ['RANDOM_GROUP_SYSTEM', 'RANGCA'])) {
                    $result = $formField['id'];
                    break;
                }
            }
        }
        return $result;
    }
    /**
     * @return array
     */
    public static function getFormFieldType(int $formId = null): array
    {
        $id = $_POST['id'];

        // 新增字段的话显示所有类型
        if (!$id || !Laminas::$serviceManager->itemForm->getIsPatientWrite($_POST['form_id'])) {
            //
            if (SDMHelper::app()->form->getGroupId($_POST['form_id']) == FormGroup::NORMAL_OCR) {
                return [
                    ['value' => FormField::FORM_FIELD_TYPE_DATE, 'label' => '日期（年月日）'],
                    ['value' => FormField::FORM_FIELD_TYPE_DATE_UK, 'label' => '日期（UK）'],
                    ['value' => FormField::FORM_FIELD_TYPE_DATE_SECOND, 'label' => '日期(年月日时分)'],
                    ['value' => FormField::FORM_FIELD_TYPE_INTEGER, 'label' => '整数'],
                    ['value' => FormField::FORM_FIELD_TYPE_FLOAT_1, 'label' => '小数（一位小数）'],
                    ['value' => FormField::FORM_FIELD_TYPE_FLOAT_2, 'label' => '小数（二位小数）'],
                    ['value' => FormField::FORM_FIELD_TYPE_FLOAT_3, 'label' => '小数（三位小数）'],
                    ['value' => FormField::FORM_FIELD_TYPE_TEXT, 'label' => '文本'],
                    ['value' => FormField::FORM_FIELD_TYPE_RADIO, 'label' => '单选'],
                    ['value' => FormField::FORM_FIELD_TYPE_CHECKBOX, 'label' => '多选'],
                    ['value' => FormField::FORM_FIELD_TYPE_UPLOAD_SHARE_IMAGE, 'label' => '上传共享图片'],
                    ['value' => FormField::FORM_FIELD_TYPE_REGION_OPTION, 'label' => '级联选择'],
                ];
            }
            return Enum::FORM_FIELD_TYPE;
        }

        $fieldType = Laminas::$serviceManager->itemFormField->fetchOne([
            'where' => ['id' => $id]
        ])['type'] ?? false;

        $fieldMap = ArrayHelper::index(Enum::FORM_FIELD_TYPE, 'value');

        // 整数型可以切换成文本
        if (
            in_array($fieldType, [
                FormField::FORM_FIELD_TYPE_INTEGER,
                FormField::FORM_FIELD_TYPE_FLOAT_1,
                FormField::FORM_FIELD_TYPE_FLOAT_2,
                FormField::FORM_FIELD_TYPE_FLOAT_3,
                FormField::FORM_FIELD_TYPE_ITEM_FORM_SOURCE,
            ])
        ) {
            return [$fieldMap[$fieldType], $fieldMap[FormField::FORM_FIELD_TYPE_TEXT]];
        }else if ($fieldType == FormField::FORM_FIELD_TYPE_TEXT) {
            // 文本 可切回项目数据源,文本域
            return [$fieldMap[$fieldType], $fieldMap[FormField::FORM_FIELD_TYPE_ITEM_FORM_SOURCE], $fieldMap[FormField::FORM_FIELD_TYPE_TEXTAREA]];
        }else if( $fieldType == FormField::FORM_FIELD_TYPE_DATETIME) {
            return [$fieldMap[$fieldType], $fieldMap[FormField::FORM_FIELD_TYPE_DATETIME_SECOND_UK]];
        }else if( $fieldType == FormField::FORM_FIELD_TYPE_DATE_SECOND) {
            return [$fieldMap[$fieldType], $fieldMap[FormField::FORM_FIELD_TYPE_DATETIME_UK]];
        }else if( $fieldType == FormField::FORM_FIELD_TYPE_DATE) {
            return [$fieldMap[$fieldType], $fieldMap[FormField::FORM_FIELD_TYPE_DATE_UK]];
        }

        if (
            in_array($fieldType, [
                FormField::FORM_FIELD_TYPE_UPLOAD_IMAGE,
                FormField::FORM_FIELD_TYPE_UPLOAD_SHARE_IMAGE,
            ])
        ) {
            return [$fieldMap[$fieldType], $fieldMap[($fieldType == FormField::FORM_FIELD_TYPE_UPLOAD_SHARE_IMAGE) ? FormField::FORM_FIELD_TYPE_UPLOAD_IMAGE : FormField::FORM_FIELD_TYPE_UPLOAD_SHARE_IMAGE]];
        }

        return [$fieldMap[$fieldType]];
    }

    /**
     * 获取排除的检查点
     * @return array
     */
    public static function getExceptCheckTime (int $formId = null): array
    {
        $itemId = $_POST['item_id'] ?? false;
        if (!$itemId) {
            return [];
        }
        $res = [];
        $query = Laminas::$serviceManager->itemChecktime->fetchAll([
            'where' => ['item_id' => $itemId]
        ]);

        $stageName = [];
        $randomPlan = [];
        foreach ($query as $item) {
            if (!isset($stageName[$item['stage_id']])) {
                $stageName[$item['stage_id']] = Laminas::$serviceManager->itemResearchstage->fetchOne([
                        'where' => ['id' => $item['stage_id']]
                    ])['stage_name'] ?? '';
            }

            if (!isset($randomPlan[$itemId][$item['flowcat_id']])) {
                $randomPlan[$itemId][$item['flowcat_id']] = Laminas::$serviceManager->itemRandom->fetchOne([
                        'where' => ['item_id' => $itemId, 'flowcat_id' => $item['flowcat_id']]
                    ])['random_name'] ?? '';
            }
            $res[] = [
                'label' => "{$stageName[$item['stage_id']]} - {$item['check_name']} ({$randomPlan[$itemId][$item['flowcat_id']]})",
                'value' => $item['id'],
            ];
        }

        return $res;
    }

    /**
     * 获取隶属于哪个检查点
     * @param $groupId
     * @return array
     */
    public static function getDsStage($groupId): array
    {
        $defaultValue = [];

        if ($groupId == FormGroup::TEST_SUMMARY) {
            $defaultValue = explode(',', FormGroup::DS_STAGE);
        }

        return [
            'type' => 'Checkbox',
            'label' => '隶属受试者状态',
            'prop' => 'ds_stage',
            'default' => $defaultValue,
            'checkboxs' => [
                ['label' => '终止', 'value' => '4'],
                ['label' => '完成', 'value' => '3'],
            ],
            'rules' => [
                [
                    'required' => false,
                    'message' => '请选择状态',
                ]
            ],
        ];
    }

    public function getCacheKey(): string
    {
        return self::class;
    }


    private function _getVersionData(): array
    {
        if (!$this->getCache(self::HELPER_KEY_FROM_VERSION)) {
            $this->setCache(Laminas::$serviceManager->itemFormVersion->fetchOne(['order' => ['id DESC'], 'where' => ['form_id' => $this->formId]]), self::HELPER_KEY_FROM_VERSION);
        }

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

    /**
     * 获取表单填写类型。
     * @see Form::FORM_TYPE_MULTI 一对多
     * @see Form::FORM_TYPE_SINGLE 一对一
     * @param int|null $formId
     * @return mixed
     * @throws Exception
     */
    public function getType(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 获取表单名称
     * @param int|null $formId
     * @return mixed|null
     * @throws Exception
     */
    public function getName(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 获取ae表单数据
     * @param int|null $itemId
     * @return mixed|null
     * @throws Exception
     */
    public function getAeForm(int $itemId = null): array
    {
        if (!$this->getCache(self::HELPER_KEY_AE_FORM)) {
            $this->setCache(Laminas::$serviceManager->itemForm->fetchOne(['where' => [
                'group_id' => FormGroup::AE,
                'is_del' => 0,
                'item_id' => $itemId
            ]]), self::HELPER_KEY_AE_FORM);
        }

        $val = $this->getCache(self::HELPER_KEY_AE_FORM);

        return $this->getProperty($val, '', '未发现AE表单。');
    }

    public function getCMINDCId(int $formId)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $version = ArrayHelper::index($this->getVersionData($formId), 'var_name');

        return $this->getProperty($version[DictionaryVarNameEnum::COLLECT_MEDICAL_TAKE_CMINDC], 'id');
    }


    /**
     * 表单类型。
     * @see FormGroup::NORMAL 常规类
     * @see FormGroup::TEST_SUMMARY 试验总结类
     * @see FormGroup::RANDOM_GROUP 随机分组
     * @see FormGroup::SAE SAE类表单
     * @see FormGroup::THROUGH_PROCESS 贯穿全程类
     * @see FormGroup::AE AE类表单
     * @see FormGroup::NORMAL_OCR 常规类(识别)
     * @see FormGroup::THROUGH_PROCESS_DO 贯穿全程识别医嘱
     * @see FormGroup::CHECK_DO 医嘱（OCR识别）
     * @see FormGroup::CHECK_OCR 检查类（OCR识别）
     * @param int|null $formId
     * @return mixed
     * @throws Exception
     */
    public function getGroupId(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    public function getItemId(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * @param int|null $formId
     * @return mixed
     * @throws Exception
     */
    public function getCheckListId(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * @param int|null $formId
     * @return mixed
     * @throws Exception
     */
    public function getIsHandwrittenSignature(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 是否有分值字段。
     * @return mixed
     * @throws Exception
     */
    public function getIsFieldScore(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 信息采集类型。不知道干啥用的。田老师让加的
     * @see Category
     * @return mixed
     * @throws Exception
     */
    public function getInfoCollectType(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 获取表单完成状态判断。
     * @see Form::FORM_FINISH_CONDITION_ALL 填写全部
     * @see Form::FORM_FINISH_CONDITION_ALL 任意填写
     * @return mixed
     * @throws Exception
     */
    public function getFinishCondition(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 是否是贯穿全程类表单。
     * @param int|null $formId
     * @return bool
     * @throws Exception
     */
    public function getIsProcess(int $formId = null): bool
    {
        if ($formId) {
            $this->formId = $formId;
        }

        return $this->getGroupId() == FormGroup::THROUGH_PROCESS ;
    }

    /**
     * 常规识别类表单锁定了是否可以编辑
     * @param int|null $formId
     * @throws Exception
     */
    public function getIdentificationEdit(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }
        $val = $this->_getCacheData();
        return $this->getProperty($val, 'identification_edit');
    }

    /**
     * 是否是识别医嘱功能。
     * @param int|null $formId
     * @return bool
     * @throws Exception
     */
    public function getIsThroughProcessDo(int $formId = null): bool
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();
        return $this->getProperty($val, 'finish_condition') == 1;
    }

    /**
     * 受试者能否填写
     * @param int|null $formId
     * @return mixed
     * @throws Exception
     */
    public function getCanPatientWrite(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 共享图片哈希值
     * @param int|null $formId
     * @return string
     * @throws Exception
     */
    public function getGcoPool(int $formId = null): string
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 表单公式。
     * @param string|null $formId
     * @return mixed
     * @throws Exception
     */
    public function getExpression(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 是否是平分类表单。
     * @param string|null $formId
     * @return mixed
     * @throws Exception
     */
    public function getIsUsingScore(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 是否是分支类型的表单公式。
     * @param int|null $formId
     * @return bool
     * @throws Exception
     */
    public function getIsScoreExpression(int $formId = null): bool
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $ex = $this->getExpression($formId);

        return !(stripos($ex, 'RESULT') === false);
    }

    /**
     * @param int|null $formId
     * @return mixed|null
     * @throws Exception
     */
    public function getCreatedAt(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getCacheData();

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

    /**
     * 与表单相关联的表单。
     * @param int|null $formId 当前表单
     * @return array|null
     */
    public function getGcoGroupForm(int $formId = null): ?array
    {
        if ($formId) {
            $this->formId = $formId;
        }

        return $this->_getGCOHashData() ?? null;
    }

    private function _getGCOHashData(): array
    {
        if (!$this->getCache(self::HELPER_KEY_GCO_POOL)) {
            $data = $this->_getCacheData();
            $this->setCache(Laminas::$serviceManager->itemForm->fetchAll(['where' => ['item_id' => $data['item_id'], 'is_del' => 0, 'gco_pool' => $this->getGcoPool(), 'group_id' => FormGroup::NORMAL_OCR]]), self::HELPER_KEY_GCO_POOL);
        }

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

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

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

        return $this->getCache();
    }

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

    /**
     * 获取表单version缓存。
     * @param string|null $formId
     * @return mixed
     * @throws Exception
     */
    public function getVersionData(int $formId = null)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        $val = $this->_getVersionData()['field'] ?? null;

        return $this->getProperty(StringHelper::jsonDecode($val));
    }

    /**
     * `
     *  如果希望生成字典项的version数据, 需要配合@see setIsDictionary 一起使用。
     * `
     * @param bool $isUpdate 生成完了是否要更新
     */
    public function generateVersion(int $formId, bool $isUpdate = false)
    {
        $model = $this->isDictionary === true ? Laminas::$serviceManager->dictionaryForm : Laminas::$serviceManager->itemForm;
        $version = $this->isDictionary === true ? Laminas::$serviceManager->dictionaryFormVersion : Laminas::$serviceManager->itemFormVersion;

        if ($isUpdate) {
            $has = $version->fetchOne([
                'where' => ['form_id' => $formId]
            ]);
            $version->save(ArrayHelper::filter([
                'field' => $model->buildFieldVersion($formId),
                'version' => 'v1.0',
                'id' => $has['id'] ?? null,
                'form_id' => $formId
            ]));
        }

        $this->isDictionary = false;
    }

    public function getIsCMINDCForm(int $formId): bool
    {
        if ($formId) {
            $this->formId = $formId;
        }

        if (!$this->getCache(__FUNCTION__)) {
            $versionData = ArrayHelper::index($this->getVersionData($formId), 'var_name');
            $this->setCache(isset($versionData[DictionaryVarNameEnum::COLLECT_MEDICAL_TAKE_CMINDC]), __FUNCTION__);
        }

        return $this->getCache(__FUNCTION__);
    }

    /**
     * 识别类表单数据是否锁定
     * @param int $formId
     * @param int|null $patientId
     * @param int|null $checkTimeId
     * @return bool
     */
    public function getIsShareFormLock(int $formId, $patientId = null, $checkTimeId = null): bool
    {
        if (!$patientId || !$checkTimeId) {
            return false;
        }

        $forms = SDMHelper::app()->form->getGcoGroupForm($formId);

        // 看看当前图片是否已经锁定了
        $allImages = Laminas::$serviceManager->patientFormContentImg->fetchAll([
            'where' => [
                'patient_id' => $patientId,
                'checktime_id' => $checkTimeId,
                'form_id' => ArrayHelper::getColumn($forms, 'id'),
                'is_del' => 0
            ]
        ]);

        return array_sum(ArrayHelper::getColumn($allImages, 'is_lock')) > 0;
    }

    public function getShareFormImages(int $formId, int $patientId, int $checkTimeId)
    {
        if ($formId) {
            $this->formId = $formId;
        }

        if (!$this->getCache(__FUNCTION__ . $formId)) {
            $sharePool = ArrayHelper::getColumn(SDMHelper::app()->form->getGcoGroupForm($formId), 'id');

            $fields = Laminas::$serviceManager->itemFormField->fetchAll([
                'where' => ['form_id' => $sharePool, 'type' => FormField::FORM_FIELD_TYPE_UPLOAD_SHARE_IMAGE]
            ]);

            $query = Laminas::$serviceManager->patientFormContentImg->fetchAll([
                'order' => ['id ASC'],
                'where' => ['field_id' => ArrayHelper::getColumn($fields, 'id'), 'patient_id' => $patientId, 'is_del' => 0, 'checktime_id' => $checkTimeId]
            ]);


            $r = [];

            foreach ($query as $image) {
                $r[] = [
                    'name' => $image['img_name'],
                    'url' => Oss::getUploadDomain() . $image['img_src'],
                ];
            }

            $this->setCache($r, __FUNCTION__ . $formId);
        }

        return $this->getCache(__FUNCTION__ . $formId);
    }

    /**
     * 获取常规识别类表单的共享图片字段
     * @throws Exception
     */
    public function getShareFormField(int $formId)
    {
        $version = ArrayHelper::index($this->getVersionData($formId), 'type');

        if (!isset($version[FormField::FORM_FIELD_TYPE_UPLOAD_SHARE_IMAGE])) {
            throw new InvalidArgumentException('表单设置有误。常规识别类表单的共享图片字段不存在');
        }

        return $version[FormField::FORM_FIELD_TYPE_UPLOAD_SHARE_IMAGE];
    }
}
