<?php

namespace Application\Service\Extension\Middleware\components;

use Application\Form\item\patient\PatientFormModel;
use Application\Service\DB\Dictionary\FormField;
use Application\Service\Exceptions\InvalidArgumentException;
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\ValidatorHelper;
use Application\Service\Extension\Identity\Identity;
use Application\Service\Extension\Laminas;
use Application\Service\Extension\Middleware\BaseMiddlewareComponent;
use Application\Service\Extension\ValidatorV2\RulesContainer;

class ValidPostData extends BaseMiddlewareComponent
{
    /**
     * 高级验证规则
     * @var array|\string[][][]
     */
    private array $validatorMap = [
        FormField::FORM_FIELD_TYPE_INTEGER => [
            [ValidatorHelper::class, 'isInteger'],
        ],
        FormField::FORM_FIELD_TYPE_FLOAT_1 => [
            [ValidatorHelper::class, 'isFloat'],
        ],
        FormField::FORM_FIELD_TYPE_FLOAT_2 => [
            [ValidatorHelper::class, 'isFloat'],
        ],
        FormField::FORM_FIELD_TYPE_FLOAT_3 => [
            [ValidatorHelper::class, 'isFloat']
        ],
        FormField::FORM_FIELD_TYPE_DATE => [
            [ValidatorHelper::class, 'isLegalDate']
        ],
        FormField::FORM_FIELD_TYPE_DATE_SECOND => [
            [ValidatorHelper::class, 'isLegalDate']
        ],
        FormField::FORM_FIELD_TYPE_DATETIME => [
            [ValidatorHelper::class, 'isLegalDate']
        ],
    ];

    private function _getVersion()
    {
        return SDMHelper::app()->setAttributes(['form_id' => $this->owner->formId])->form->getVersionData();
    }

    private function _getForm(): \Application\Service\Extension\Helper\FormHelper
    {
        return SDMHelper::app()->setAttributes(['form_id' => $this->owner->formId])->form;
    }

    public $isError = 0;

    public $errors = [];

    function execute($isError = 0)
    {
        $this->isError = $isError;
        // 是否有基点日期
        $this->hasAnchorTime();

        // 数据验证规则。数字，文本一类的验证
        $this->validData();

        // 验证当前表单是否允许受试者填写
        $this->validCanPatientWrite();

        // 验证分值是否正确
        $this->validScore();

        if($isError == 1) return $this->errors;
    }

    /**
     * 是否有基点日期
     * @param PatientFormModel $this->owner
     */
    private function hasAnchorTime()
    {
        // 评分
        if ($this->owner->scenario === PatientFormModel::SCENARIO_USING_SCORE) {
            return;
        }

        // 当前填写的检查点
        $currentPatientCheckTime = Laminas::$serviceManager->itemPatientchecktime->memoryCache()->fetchOne([
            'where' => [
                'item_id' => $this->owner->validator->attributes['item_id'],
                'patient_id' => $this->owner->validator->attributes['patient_id'],
                'checktime_id' => $this->owner->validator->attributes['checktime_id'],
            ]
        ]);

        if (!$currentPatientCheckTime) {
            return;
        }

        // 查一下检查点日期
        $checkTime = Laminas::$serviceManager->itemChecktime->memoryCache()->fetchOne([
            'order' => ['check_order DESC'],
            'where' => ['id' => $this->owner->validator->attributes['checktime_id']]
        ]) ?: false;

        //试验总结类的表单 跳过验证
        if($checkTime['is_del'] == 9){
            return;
        }
        $field = $checkTime['field_id'];

        // 字段数据
        $field = Laminas::$serviceManager->itemFormField->memoryCache()->fetchOne(['where' => ['id' => $field]]);

        // 字段所属表单名称
        $form = Laminas::$serviceManager->itemForm->memoryCache()->fetchOne(['where' => ['id' => $field['form_id']]]);

        $allCheckId = Laminas::$serviceManager->itemCheckcontent->memoryCache()->fetchAll([
            'columns' => ['check_id'],
            'where' => ['form_id' => $form['id'], 'is_del' => 0]
        ]);

        $topCheckTime = Laminas::$serviceManager->itemChecktime->memoryCache()->fetchOne([
            'order' => ['check_order ASC'],
            'where' => ['id' => ArrayHelper::getColumn($allCheckId, 'check_id')]
        ]) ?: false;

        // 阶段名称
        $stageName = Laminas::$serviceManager->itemResearchstage->memoryCache()->fetchOne(['where' => ['id' => $topCheckTime['stage_id']]])['stage_name'] ?? '';

        if (!$currentPatientCheckTime['anchor_date'] && $form['id'] != $this->owner->validator->attributes['form_id']) {
            if($this->isError == 1){
                $this->errors[] = "{$stageName} / {$topCheckTime['check_name']} - {$form['name']} / {$field['name']} 未填写, 请补充！";
            }else{
                throw new InvalidArgumentException("{$stageName} / {$topCheckTime['check_name']} - {$form['name']} / {$field['name']} 未填写, 请补充！");
            }
        }
    }

    /**
     * 数据类型验证
     */
    private function validData()
    {
        $versionData = $this->_getVersion();
//        var_dump($this->owner->postData);die;
        foreach ($this->owner->postData as $k => &$data) {
//            if($k <> 266100) continue;
            if (!DataHelper::isField($k)) {
                continue;
            }
            // 取字段的id
            $fieldId = DataHelper::getFieldId($k);
            // 空数据不验证
            if (isset($versionData[$fieldId]) && $data !== '') {
                if (isset($this->validatorMap[$versionData[$fieldId]['type']])) {
                    $fieldVersionData = $versionData[$fieldId];
                    // 所有的验证规则
                    $validators = $this->validatorMap[$fieldVersionData['type']];
                    foreach ($validators as $validator) {
                        $isValid = call_user_func_array($validator, [&$data, $fieldVersionData]);
                        if ($isValid !== true) {
                            throw new InvalidArgumentException(" `{$versionData[$fieldId]['name']}` $isValid");
                        }
                    }
                }
            }
            // 设置了rules
            if (isset($versionData[$fieldId]) && isset($versionData[$fieldId]['rules']) && $versionData[$fieldId]['rules'] && isset($versionData[$fieldId]['remind_type']) && $versionData[$fieldId]['remind_type'] == 1) {
                /** @var RulesContainer $rulesContainer */
                $rulesContainer = unserialize($versionData[$fieldId]['rules']);
                $rulesContainer->setAttributes([$fieldId => $data]);
                $rulesContainer->setAttributeLabel([$fieldId => $rulesContainer->label]);
                if($this->isError == 1){
                    $result = $rulesContainer->execute($fieldId,$this->isError);
                    if(!empty($result)){
                        foreach ($result as $v){
                            $this->errors[] = $v;
                        }
                    }
                }else{
                    $rulesContainer->execute($fieldId);
                }

            }
        }
    }

    /**
     * 验证前端提交的分值是否正确
     */
    private function validScore()
    {
        if (!$this->_getForm()->getIsFieldScore()) {
            return;
        }

        $versionData = $this->_getVersion();
        $getScore = function($fieldId, $fieldVal) use ($versionData) {
            if (!isset($versionData[$fieldId]) || !isset($versionData[$fieldId]['children'])) {
                return false;
            }

            $c = ArrayHelper::index($versionData[$fieldId]['children'], 'value');
            if (is_array($fieldVal)) {
                $score = false;
                foreach ($fieldVal as $v) {
                   // $score += intval($c[$v]['score']);
                    $score += $c[$v]['score'] + 0;
                }
                return $score;
            } else {
                // 不是分值选项
                if ($c[$fieldVal]['is_score'] == 0) {
                    return false;
                }
            }
            return $c[$fieldVal]['score']+0;
        };

        $totalScore = false;
        $scoreStr = $fixedScoreStr = [];
        foreach ($this->owner->postData as $field => $value) {
            if (DataHelper::isField($field) === true && $value !== '') {
                $firstLevelFieldId = DataHelper::getFieldId($field);
                $score = $getScore($firstLevelFieldId, $value);
                if ($score !== false) {
                    $scoreStr[$field] = $score;
                    $fixedScoreStr[] = [
                        "prop" => strval($field),
                        "score" => $score+0,
                        "is_score" => true
                    ];
                    $totalScore += $score+0;
                }
            }
        }

        if (!$totalScore) {
            return;
        }

        // 根本没点击过分值的选项
        if ((!isset($this->owner->postData['scoreStr']) || !isset($this->owner->postData['score']))) {
            $this->owner->postData['scoreStr'] = json_encode($fixedScoreStr);
            $this->owner->postData['score'] = $totalScore;
//            throw new InvalidArgumentException('分值参数缺失, 请刷新页面重新填写!');
        }

        $postScoreStr = ArrayHelper::index(StringHelper::jsonDecode($this->owner->postData['scoreStr']), 'prop');

        foreach ($scoreStr as $field => $strScore) {
            $strScore = $strScore+0;
            if(isset($postScoreStr[$field])){
                $postScoreStr[$field]['score'] = $postScoreStr[$field]['score']+0;
            }
            if (!isset($postScoreStr[$field]) || $strScore != $postScoreStr[$field]['score']) {
                if($this->isError == 1){
                    $this->errors[] = '分值选项数据有误, 请刷新页面重新填写!';
                }else{
                    throw new InvalidArgumentException('分值选项数据有误, 请刷新页面重新填写!');
                }
            }
        }
        $totalScore = $totalScore+0;
        $this->owner->postData['score'] = $this->owner->postData['score']+0;
        if ($totalScore != $this->owner->postData['score']) {
            if($this->isError == 1){
                $this->errors[] = '总分值计算有误, 请刷新页面重新填写!';
            }else{
                throw new InvalidArgumentException('总分值计算有误, 请刷新页面重新填写!');
            }
        }
    }

    /**
     * 是否允许受试者填写
     */
    private function validCanPatientWrite()
    {
        $platForm = Laminas::$serviceManager->identity->getPlatform();

        // 当前登录用户是否为受试者
        if (Identity::PLATFORM_MINI_PROGRAM_PATIENT == $platForm) {
            if (!$this->_getForm()->getCanPatientWrite()) {
                if($this->isError == 1){
                    $this->errors[] = '当前表单不允许受试者填写';
                }else{
                    throw new InvalidArgumentException('当前表单不允许受试者填写');
                }
            }
        }
    }
}