<?php

namespace Application\Form\item;

use Application\Common\Enum;
use Application\Common\EventEnum;
use Application\Service\DB\AbstractDb;
use Application\Service\DB\Db;
use Application\Service\DB\Dictionary\FormField;
use Application\Service\DB\Dictionary\FormGroup;
use Application\Service\Extension\Event;
use Application\Service\Extension\Events\ItemFormEventHandler;
use Application\Service\Extension\Helper\ArrayHelper;
use Application\Service\Extension\Helper\SDMHelper;
use Application\Service\Extension\Helper\StringHelper;
use Application\Service\Extension\Laminas;
use Application\Service\Extension\Validator\ValidatorApplication;
use Laminas\Db\Sql\Predicate\In;
use Laminas\Db\Sql\Predicate\Operator;
use Laminas\Validator\Exception\InvalidArgumentException;

class FormForm extends \Application\Form\FormForm
{
    public function __construct(ValidatorApplication $validator = null)
    {
        parent::__construct($validator);
        Event::on(EventEnum::EVENT_AFTER_ITEM_FORM_CREATE, [ItemFormEventHandler::class, 'afterItemFormCreate']);
    }

    protected function getForm():AbstractDb
    {
        return Laminas::$serviceManager->itemForm;
    }

    protected function getFormField()
    {
        return Laminas::$serviceManager->itemFormField;
    }

    protected function getFormRadio()
    {
        return Laminas::$serviceManager->itemFormFieldRadio;
    }

    protected function getFormText()
    {
        return Laminas::$serviceManager->itemFormFieldText;
    }

    protected function getFormVersion()
    {
        return Laminas::$serviceManager->itemFormVersion;
    }

    /**
     * 验证AE, SAE, 实验总结, 随机分组类是否已经创建了多个
     * @param $value
     * @return void|null
     */
    public function invalidGroupId($value)
    {
        if (!in_array($value, [FormGroup::AE, FormGroup::SAE, FormGroup::RANDOM_GROUP])) {
            return null;
        }

        if ($_POST['id']) {
            $query = $this->getForm()->fetchOne([
                'columns' => ['id'],
                'where' => ['is_del' => 0, 'item_id' => $_POST['item_id'], 'group_id' => $value]
            ]);

            if ($query['id'] != $_POST['id']) {
                throw new InvalidArgumentException("此类型表单只能设置一个, 请勿重复添加");
            }
        } else {
            if (
                Laminas::$serviceManager->itemForm->fetchOne([
                    'where' => [
                        'item_id' => $_POST['item_id'],
                        'group_id' => $value,
                        'is_del' => 0
                    ]
                ])
            ) {
                throw new InvalidArgumentException("此类型表单只能设置一个, 请勿重复添加");
            }
        }

        return null;
    }

    /**
     * 验证字典项表单名称是否添加重复
     * @param $value
     * @return null
     */
    public function invalidCreateName($value)
    {
        $request = Laminas::$app->getMvcEvent()->getRequest();

        if ($value !== null) {
            // 没 id 说明是新增, 有 id 是编辑
            $id = $request->getPost('id');

            // 新增
            if (!$id) {
                $query = $this->getForm()->fetchOne([
                    'columns' => ['id'],
                    'where' => ['name' => $request->getPost('name'), 'is_del' => 0, 'item_id' => $request->getPost('item_id')]
                ]);

                if ($query) {
                    throw new InvalidArgumentException("表单名称 {$value} 已存在, 请勿重复添加。");
                }

            } else {
                $query = $this->getForm()->fetchOne([
                    'columns' => ['id'],
                    'where' => ['name' => $request->getPost('name'), 'is_del' => 0, 'item_id' => $request->getPost('item_id')]
                ]);

                if ($query && (count($query) > 1 || $query['id'] != $request->getPost('id'))) {
                    throw new InvalidArgumentException("表单名称 {$value} 已在其他表单中使用, 请勿重复添加[e-2]。");
                }
            }
        }

        return null;
    }

    /**
     * 验证删除表单id
     * @return null
     */
    public function invalidDeleteId($val)
    {
        $request = Laminas::$app->getMvcEvent()->getRequest();

        $formData = Laminas::$serviceManager->itemForm->fetchOne([
            'where' => ['id' => $request->getPost('id')]
        ]);

        if (Laminas::$serviceManager->patientFormContent->fetchOne(['where' => [
            'item_id' => $formData['item_id'],
            'form_id' => $formData['id'],
            'is_del' => 0
        ]])) {
            throw new InvalidArgumentException("当前表单已有受试者填写。无法进行删除操作。", 1001);
        }

        //查询一下该form下的字段ID
        $form_fileids = Laminas::$serviceManager->itemFormField->fetchCol('id',['is_del' => 0,'form_id' => $formData['id']]);
        $relation_where = ['form_id' => $formData['id'], 'is_del' => 0, new Operator('relation_form_id', Operator::OP_NE, 0)];
        if(!empty($form_fileids)){
            $relation_where[] = ['field_id'=> StringHelper::toArray($form_fileids)];
        }

        if (Laminas::$serviceManager->itemFormRelation->getCount($relation_where)) {
            throw new InvalidArgumentException("当前表单下已有其他关联表单。无法进行删除操作。请解除关联关系。", 1001);
        }

        if (Laminas::$serviceManager->itemFormFieldRadio->getCount([new \Laminas\Db\Sql\Predicate\Expression("FIND_IN_SET('$val',relation_information)")])) {
            throw new InvalidArgumentException("当前表单已被其他表单关联。无法进行删除操作。请解除关联关系。", 1001);
        }

        return null;
    }

    public function validVarName($val)
    {
        $request = Laminas::$app->getMvcEvent()->getRequest();

        $originData = $this->getForm()->fetchOne([
            'where' => ['id' => $request->getPost('id')]
        ]);

        // 如果有受试者填写过数据, 有些数据不允许更改
        if ($originData) {
            if (Laminas::$serviceManager->itemForm->getIsPatientWrite($request->getPost('id'))) {
                $labelMap = [
                    'type' => '类型',
                    'group_id' => '表单类型',
                ];

                foreach ($labelMap as $field => $label) {
                    if ($originData[$field] != $request->getPost($field)) {
                        throw new \Application\Service\Exceptions\InvalidArgumentException("已有受试者数据。无法更改 `{$label}`");
                    }
                }
            }
        }


        if ($request->getPost('form_type') == FormField::FORM_CONFIG_RADIO && !$val) {
            return null;
        }

        //检查点变量名规则
        $isMatched = preg_match('/^[a-zA-Z_]([a-zA-Z0-9_]+)?$/', $val);
        if (!$isMatched) {
            throw new \Laminas\Validator\Exception\InvalidArgumentException("变量名必须以A-Z（不区分大小写）或下划线（_）开始,且不能包括空格和特殊符号。", 1001);
        }
        if (strlen($val) > 32) {
            throw new \Application\Service\Exceptions\InvalidArgumentException("不能超过32个字符", 1001);
        }

        // 验证变量名不能重复
        // 【新系统】变量名，新加不可重复的控制 --李总，白老师
        //https://e.gitee.com/yikeen_project/dashboard?issue=I72KSD
        // 没 id 说明是新增, 有 id 是编辑
        $where = ['item_id' => $request->getPost('item_id'), 'var_name' => $val, 'is_del' => 0];
        $condition = $request->getPost('id') ? [new Operator('id', Operator::OP_NE, $request->getPost('id'))] : null;
        if ($condition !== null) {
            $where = ArrayHelper::merge($where, $condition);
        }
        $data = $this->getForm()->fetchAll([
            'columns' => ['var_name', 'id', 'name'],
            'where' => $where
        ]);

        // 新增
        if ($request->getPost('id')) {
            if (count($data) > 1) {
                throw new InvalidArgumentException("变量名 `{$val}` 已与 `{$data['name']}` 中的变量名重复, 请勿重复添加。", 1001);
            }

            $data = current($data);
            if ($data && $data['id'] != $request->getPost('id')) {
                throw new InvalidArgumentException("变量名 `{$val}` 已与 `{$data['name']}` 中的变量名重复, 请勿重复添加。", 1001);
            }
            $c = 1;
        } else {
            $c = 0;
        }

        if ($data && (count($data) > $c || current(ArrayHelper::getColumn($data, 'var_name')) != $request->getPost('var_name'))) {
            $formName = current($data)['name'];
            throw new InvalidArgumentException("变量名 `{$val}` 已与 `{$formName}` 中的变量名重复, 请勿重复添加。", 1001);
        }

        return null;
    }

    public function validGcoPool($value)
    {
        // 编辑
        if ($_POST['id']) {
            $isWrite = Laminas::$serviceManager->patientForm->fetchAll([
                'columns' => ['id'],
                'where' => [
                    'form_id' => ArrayHelper::getColumn(SDMHelper::app()->form->getGcoGroupForm($_POST['id']), 'id'),
                    'is_del' => 0
                ]
            ]);

            // 没产生数据随便编辑。
            if (!$isWrite) {
                return;
            }

            $originGcoPool = SDMHelper::app()->form->getGcoPool($_POST['id']);

            $currentGcoPool = $value;

            if ($originGcoPool != $currentGcoPool) {
                throw new InvalidArgumentException("已产生数据的表单, 识别分组无法更改。");
            }
        }

        return ;
    }

    /**
     * 进度管理
     * 创建项目表单
     * @return int
     */
    public function createForm(): int
    {
        $this->event = EventEnum::EVENT_DICTIONARY_FORM_CREATE;

        Db::beginTransaction();

        // 实验总结类默认勾选所有隶属实验总结类检查点
        if ($this->validator->attributes['group_id'] == FormGroup::TEST_SUMMARY) {
            $this->validator->attributes['ds_stage'] = FormGroup::DS_STAGE;
        }

        $formId = Laminas::$serviceManager->itemForm->insert([
            'name' => $this->validator->attributes['name'],
            'type' => $this->validator->attributes['type'],
            'item_id' => $this->validator->attributes['item_id'],
            'is_patient' => ($this->validator->attributes['is_patient'] ?? '') ?: '',
            'finish_condition' => $this->validator->attributes['finish_condition'],
            'is_required' => $this->validator->attributes['is_required'],
            'checklist_id' => $this->validator->attributes['checklist_id'],
            'create_user_id' => Laminas::$serviceManager->identity->getId(),
            'order' => $this->validator->attributes['order'],
            'group_id' => $this->validator->attributes['group_id'],
            'show_type' => $this->validator->attributes['show_type'],
            'reference_file' => $this->validator->attributes['reference_file'],
            'rdg_type' => $this->validator->attributes['rdg_type'] ?? 0,
            'var_name' => $this->validator->attributes['var_name'] ?: '',
            'expression' => $this->validator->attributes['expression'] ?: '',
            'code' => $this->validator->attributes['code'] ?? '',
            'except_checktime' => $this->getExceptCheckTime(),
            'is_handwritten_signature' => $this->validator->attributes['can_patient_write'] ?? 0,
            'ds_stage' => $this->validator->attributes['ds_stage'] ?? 1,
            'guide' => $this->validator->attributes['guide'] ?? '',
            'is_using_score' => $this->validator->attributes['is_using_score'] ?? 0,
            'is_through_process_do' => $this->validator->attributes['is_through_process_do'] ?? 0,
            'info_collect_type' => $this->validator->attributes['info_collect_type'] ?? 0,
            'gco_pool' => $this->validator->attributes['gco_pool'] ?? '',
            'is_patient_general_info' => $this->validator->attributes['is_patient_general_info'] ?? '',
            'identification_edit' => ArrayHelper::getValue($this->validator->attributes, 'identification_edit', 0),
            'is_export' => ArrayHelper::getValue($this->validator->attributes, 'is_export', 0),
            'is_more_sdv' => ArrayHelper::getValue($this->validator->attributes, 'is_more_sdv', 0)
        ]);

        // 添加随机分组字段
        $this->initRandomGroupField($formId, $this->validator->attributes['rdg_type'] ?? 0);

        if ($this->validator->attributes['checklist_id'] || $this->validator->attributes['group_id'] == FormGroup::CHECK_DO) {
            $this->initCheckListField($formId);
        }

        // 医嘱识别
        if ($this->validator->attributes['group_id'] == FormGroup::THROUGH_PROCESS && $this->validator->attributes['is_through_process_do'] == 1) {
            if ($this->validator->attributes['type'] == 0) {
                throw new \Application\Service\Exceptions\InvalidArgumentException('识别医嘱的类型不能为一对一');
            }
            // 初始化贯穿全程识别医嘱表单字段
            $this->initThroughProcessDoField($formId);
        }

        Event::trigger(EventEnum::EVENT_AFTER_ITEM_FORM_CREATE, [$this]);

        Db::commit();

        return $formId;
    }

    /**
     * 获取未选中的检查点
     * 前端提交过来的是选中的检查点, 需要处理一下
     * @return string
     */
    private function getExceptCheckTime(): string
    {
        if (!isset($this->validator->attributes['except_checktime'])) {
            return '';
        }

        $allCheckTime = Laminas::$serviceManager->itemChecktime->fetchAll([
            'columns' => ['id'],
            'where' => ['item_id' => $this->validator->attributes['item_id']]
        ]);

        $exceptCheckTime = explode(',', $this->validator->attributes['except_checktime']);

        if (!$exceptCheckTime) {
            return '';
        }

        foreach ($allCheckTime as $key => $item) {
            if (in_array($item['id'], $exceptCheckTime)) {
                unset($allCheckTime[$key]);
            }
        }

        return implode(',', array_values(ArrayHelper::getColumn($allCheckTime, 'id')));
    }

    /**
     * 编辑项目表单
     * @return array
     * @throws \Exception
     */
    public function editForm()
    {
        Db::beginTransaction();

        // 随机分组处理
        $rdgType = $this->validator->attributes['rdg_type'] ?? 0;

        $originData = Laminas::$serviceManager->itemForm->fetchOne([
            'where' => ['id' => $this->validator->attributes['id']]
        ]);

        // 随机分组类型 1:手动新增;2:系统随机获取;
        $originRdgType = $originData['rdg_type'] ?: 0;
        $itemId = $originData['item_id'] ?: 0;

        // 修改了随机分组随机号分配类型, 就去处理一些东西
        if ($originRdgType && $originRdgType != $rdgType) {
            if ($rdgType == 1) {
                Laminas::$serviceManager->patient->delGroupAndNumber($itemId,1); // 0手改自，1自改手
            } elseif ($rdgType == 2) {
                Laminas::$serviceManager->patient->delGroupAndNumber($itemId,0); // 0手改自，1自改手
            }
        }

        Laminas::$serviceManager->itemForm->save([
            'id' => $this->validator->attributes['id'],
            'name' => $this->validator->attributes['name'],
            'type' => $this->validator->attributes['type'],
            'is_patient' => $this->validator->attributes['is_patient'],
            'finish_condition' => $this->validator->attributes['finish_condition'],
            'is_required' => $this->validator->attributes['is_required'],
            'checklist_id' => $this->validator->attributes['checklist_id'],
            'order' => $this->validator->attributes['order'],
            'group_id' => $this->validator->attributes['group_id'],
            'show_type' => $this->validator->attributes['show_type'],
            'reference_file' => $this->validator->attributes['reference_file'],
            'rdg_type' => $rdgType,
            'expression' => $this->validator->attributes['expression'] ?: '',
            'var_name' => $this->validator->attributes['var_name'] ?: '',
            'can_patient_write' => $this->validator->attributes['can_patient_write'] ?: 0,
            'except_checktime' => $this->getExceptCheckTime(),
            'is_handwritten_signature' => $this->validator->attributes['is_handwritten_signature'] ?? 0,
            'ds_stage' => $this->validator->attributes['ds_stage'] ?: 1,
            'guide' => $this->validator->attributes['guide'] ?: '',
            'is_using_score' => $this->validator->attributes['is_using_score'] ?: 0,
            'info_collect_type' => call_user_func(function () {
                $r = $this->validator->attributes['info_collect_type'] ?: 0;
                Laminas::$serviceManager->patientFormContentImg->isSetInfo(false)->update(['info_collect_type' => $r], ['form_id' => $this->validator->attributes['id']]);
                return $r;
            }),
            'gco_pool' => $this->validator->attributes['gco_pool'] ?? '',
            'is_patient_general_info' => $this->validator->attributes['is_patient_general_info'] ?? '',
            'identification_edit' =>  ArrayHelper::getValue($this->validator->attributes, 'identification_edit', 0),
            'is_export' => ArrayHelper::getValue($this->validator->attributes, 'is_export', 0),
            'is_more_sdv' => ArrayHelper::getValue($this->validator->attributes, 'is_more_sdv', 0)
        ]);

        $randomGroupId = Laminas::$serviceManager->itemFormField->fetchOne([
            'where' => [
                'var_name' => ['RANGC', 'RANGCA'],
                'form_id' => $this->validator->attributes['id']
            ]
        ]);

        // 如果当前表单是随机分组表单, 变更了随机分组类型, 需要同步修改生成出来的随即表单的变量和随机分组(研究分组)展示方式。
        // 手写是单选, 系统分配是下拉框。
        if ($randomGroupId) {
            $type = $rdgType == 1 ? Enum::FORM_FIELD_TYPE_RADIO : Enum::FORM_FIELD_TYPE_DROPDOWN;
            $varName = $rdgType == 1 ? 'RANGC' : 'RANGCA';
            Laminas::$serviceManager->itemFormField->update([
                'type' => $type,
                'var_name' => $varName
            ], ['id' => $randomGroupId['id']]);

            Laminas::$serviceManager->itemFormFieldText->update([
                'var_name' => $varName
            ], ['field_id' => $randomGroupId['id']]);
        }

        Laminas::$serviceManager->itemFormVersion->generate($this->validator->attributes['id']);

        Db::commit();
        return [];
    }
}