<?php

namespace Application\Service\Extension\Middleware\components;

use Application\Common\Com;
use Application\Common\EventEnum;
use Application\Common\EventEnumV2;
use Application\Form\item\patient\PatientFormModel;
use Application\Service\DB\Dictionary\FormField;
use Application\Service\DB\Dictionary\ItemForm;
use Application\Service\Exceptions\InvalidArgumentException;
use Application\Service\Extension\Helper\ArrayHelper;
use Application\Service\Extension\Helper\components\ExpressionHelper;
use Application\Service\Extension\Helper\DataHelper;
use Application\Service\Extension\Helper\DateHelper;
use Application\Service\Extension\Helper\SDMHelper;
use Application\Service\Extension\Helper\StringHelper;
use Application\Service\Extension\Middleware\BaseMiddlewareComponent;
use Application\Service\Extension\Laminas;
use Exception;
use Laminas\Stdlib\ArrayUtils;

/**
 * 对表单数据进行预处理，或者对数据做自动的矫正
 */
class Preprocessing extends BaseMiddlewareComponent
{
    /** @var PatientFormModel */
    public $owner;

    public string $middlewareName = '数据预处理中间件';

    public function __construct(array $params = [])
    {
        parent::__construct($params);
    }

    public $isError = 0;

    public $errors = [];
    /**
     * @throws Exception
     */
    function execute($isError = 0)
    {
        $this->isError = $isError;
        // 已删除的数据不做任何的数据处理
        $this->validDel();

        // 预处理数据，多字段, 字段提交数据格式做处理
        $this->prePostData();

        // 对小程序uk类型日期做处理。小程序是空值, 但是pc是--
        $this->preUK();

        // 预处理公式, 分值会自己做矫正
        $this->preExpression();

        $this->addShareFormImage();

        // 处理随机号
        $this->generateRandom();

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

    /**
     * @note 验证数据是否已删除
     * @return void
     * @throws Exception
     */
    private function validDel()
    {
        // 只有非新增操作才做删除数据验证
        if (
            !in_array( $this->owner->event, [
                    EventEnumV2::getVal(EventEnumV2::EVENT_FORM_CONTENT_CREATE),
                    EventEnum::EVENT_FORM_CONTENT_TEMP_STORAGE,
                ]
            )
                &&
            SDMHelper::app()->formContent->isDel((int)$this->owner->postData['id']) == 1
        ) {
            if($this->isError == 1){
                $this->errors[] = '此表单数据已删除，请勿做任何的操作！';
            }else{
                throw new InvalidArgumentException('此表单数据已删除，请勿做任何的操作！');
            }
        }
    }

    /**
     * 根据提交的研究分层获取对应的随机号/随机分组
     * @return void
     * @throws Exception
     */
    private function generateRandom() {
        if ($this->owner->event == EventEnumV2::getVal(EventEnumV2::EVENT_FORM_CONTENT_CREATE)) {
            // 判断当前表单是否是系统随机分组表单
            if( $system_random_field_id = SDMHelper::app()->getFormHelper()->getSystemRandomFieldId() ) {
                $randomDetails = Laminas::$serviceManager->itemRandomdetails->getRandomdetailsNumberPop(
                    $this->owner->postData['item_id'],
                    $this->owner->postData['itemsig_id'],
                    $this->owner->postData['patient_id'],
                    $this->owner->postData[$system_random_field_id]
                );

                if(empty(current($randomDetails)['rand_number']['id'] ?? [])){
                    if($this->isError == 1){
                        $this->errors[] = '已无可用的【 随机号/方案分组 】';
                    }else{
                        throw new InvalidArgumentException('已无可用的【 随机号/方案分组 】');
                    }
                }

                $randomNumberFormFieldKey = "{$this->owner->postData[$system_random_field_id]}-{$system_random_field_id}-{$this->owner->postData[$system_random_field_id]}";
                $this->owner->systemRandomFieldKey = $randomNumberFormFieldKey;
                $this->owner->postData[$randomNumberFormFieldKey] = current($randomDetails)['rand_number']['id'] ?? 0;
            }
        }
    }

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

    private function addSHareFormImage()
    {
        // 通过质疑沟通修改数据
        if ($this->owner->event == EventEnumV2::getVal(EventEnumV2::EVENT_FORM_CONTENT_EDIT_BY_LOGIC_REPLY)) {
            $oldData = Laminas::$serviceManager->patientFormContent->getOneFieldVal('data','id = '.$this->owner->postData['id']);
            $oldData = json_decode($oldData,true);

            $this->owner->postData = ArrayUtils::merge($oldData,$this->owner->postData, true);

        }
    }
    private function OLDaddSHareFormImage()
    {
        // 通过质疑沟通修改数据
        if ($this->owner->event == EventEnumV2::getVal(EventEnumV2::EVENT_FORM_CONTENT_EDIT_BY_LOGIC_REPLY)) {
            // 如果可以编辑, 先看看图片是否有修改。有修改就不让提
            $versionData = SDMHelper::app()->form->getVersionData($this->owner->formId);
            $shareFormFieldId = ArrayHelper::index($versionData, 'type')[FormField::FORM_FIELD_TYPE_UPLOAD_SHARE_IMAGE]['id'] ?? null;
            if ($shareFormFieldId === null) {
                throw new InvalidArgumentException('获取共享图片字段失败。');
            }

            $images = SDMHelper::app()->form->getShareFormImages($this->owner->formId, $this->owner->patientId, $this->owner->checktimeId);
            $this->owner->postData[$shareFormFieldId] = $images;
//            $postImages = StringHelper::jsonDecode($this->owner->postData[$shareFormFieldId], true);
//            if (count($images) !== count($postImages) || ArrayHelper::diff($images, $postImages)) {
//                throw new InvalidArgumentException('修改图片请解锁。');
//            }
        }
    }

    /**
     * 预处理提交数据
     * @return bool
     */
    private function prePostData()
    {
        $versionData = $this->_getVersion();
        foreach ($this->owner->postData as $key => &$datum) {

            // 如果是图片类型, 传过来的`[]` 要转换成空数组
            if (in_array($versionData[DataHelper::getFieldId($key)]['type'] ?? false, [FormField::FORM_FIELD_TYPE_UPLOAD_SHARE_IMAGE, FormField::FORM_FIELD_TYPE_UPLOAD_IMAGE]) && $datum === '[]') {
                $datum = [];
            }

            // 如果有`,`, 并且不是json格式。前端传图会传json格式
            if ($datum && stripos($datum, ',') !== false && StringHelper::jsonDecode($datum, false) === false) {
                $type = $versionData[DataHelper::getFieldId($key)]['type'] ?? false;
                // 多选需要分割成数组
                if ($type == FormField::FORM_FIELD_TYPE_CHECKBOX) {
                    $datum = explode(',', $datum);
                    $this->h()->log->setTraceAttach("{$this->middlewareName} 对提交数据进行了预处理, 对多选类型的数据 `{$key}` 进行了转数组处理。");
                }
            }
        }

        // 去除多余的字段
        foreach ($this->owner->postData as $postFieldId => $item) {
            if (!DataHelper::isField($postFieldId)) {
                continue;
            }

            if (stripos($postFieldId, '-') !== false) {
                $formatVal = ItemForm::splitField($postFieldId); //($postFieldId);
                $level = count($formatVal);
                foreach ($formatVal as $formatValItem) {
                    // 判断提交过来的数据
                    foreach ($this->owner->postData as $k => $v) {
                        $field = DataHelper::getFieldId($k);
                        // 一对多
                        if (isset($versionData[$field]) && $versionData[$field]['type'] == FormField::FORM_FIELD_TYPE_CHECKBOX) {
                            // 有些多选是数组的 有些是字符串
                            $val = is_array($v) ? $v : explode(',', $v);
                            if (DataHelper::getFieldId($k) == $formatValItem[0] && in_array($formatValItem[1], $val)) {
                                $level--;
                            }
                        } elseif (DataHelper::getFieldId($k) == $formatValItem[0] && $v == $formatValItem[1]) {
                            $level--;
                        }
                    }
                }

                if ($level !== 0) {
                    unset($this->owner->postData[$postFieldId]);
                    $this->h()->log->setTraceAttach("{$this->middlewareName} 对提交数据进行了预处理, 移除了不属于当前表单的数据 `{$postFieldId}`。");
                    // throw new InvalidArgumentException('数据格式错误。请刷新页面重试。');
                }
            }
        }

        return true;
    }

    /**
     * 预处理小程序UK类型数据
     */
    private function preUK()
    {
        $version = $this->_getVersion();
        foreach ($this->owner->postData as $field => &$value) {
            // 【新系统】我们所以系统所以项目所以表单，日期设置UK类型，我们统一排查处理一下，如果没填，统一处理为空的 --美
            //https://e.gitee.com/yikeen_project/dashboard?issue=I9EUL7
            // 小程序日期清空会变成空字符串, 要改成`--`
            if (DataHelper::isField($field) && isset($version[DataHelper::getFieldId($field)])) {
                if ($value && $value != '--' && Com::isValidDateField($version[DataHelper::getFieldId($field)]['type'])) {
                    // 如果是有效的时间值，则进行二次时间值格式化（标准格式）
                    $value = DateHelper::normalizeDatetime($value);
                }else {
                    if ($version[DataHelper::getFieldId($field)]['type'] == FormField::FORM_FIELD_TYPE_DATE_UK && $value === '') {
                        $value = '--';
                        $this->h()->log->setTraceAttach("{$this->middlewareName} 对提交数据进行了预处理, 对UK类型的日期 `{$field}` 进行了空处理。已将空数据替换为 `--`。");
                    }
                }
            }
        }
    }

    /**
     * 预处理公式数据
     * @throws Exception
     */
    private function preExpression()
    {
        if (!$this->h()->form->getExpression($this->owner->formId)) {
            unset($this->owner->postData['scoreResult']);
            return;
        }

        $version = $this->h()->form->getVersionData($this->owner->formId);
        $values = [];
        foreach ($this->owner->postData as $field => $value) {
            $field = DataHelper::getFieldId($field);
            if (isset($version[$field]) && $version[$field]['var_name']) {
                $values[$version[$field]['var_name']] = $value;
            }
        }
        // 公式分值矫正
        if (SDMHelper::app()->form->getIsScoreExpression($this->owner->formId)) {
            $expression = ExpressionHelper::handleExpression($this->h()->form->getExpression($this->owner->formId));
            $execVal = $this->h()->expression->setValues($values)->setExpression($expression)->execute()->getExecuteVal();
            if ($this->owner->postData['scoreResult'] === null || $this->owner->postData['scoreResult'] != intval($execVal)) {
                $this->owner->postData['scoreResult'] = intval($execVal);
                $this->h()->log->setTraceAttach("{$this->middlewareName} 对提交数据进行了预处理, 对有公式分值的表单进行了分值矫正。");
            }
        } else { // 变量公式计算矫正
            $expression = $this->h()->form->getExpression($this->owner->formId);
            $ex = explode('=', $expression);
            $resVarName = trim($ex[0]);
            $expression = ExpressionHelper::handleExpression($expression);
            $varNameIndexVersion = ArrayHelper::index($version, 'var_name');

            $execVal = $this->h()->expression->setValues($values)->setExpression($expression)->execute()->getExecuteVal();
            if ($this->owner->postData[$varNameIndexVersion[$resVarName]['id']] != $execVal) {
                if ($this->owner->postData[$varNameIndexVersion[$resVarName]['id']] == '') {
                    $this->owner->postData[$varNameIndexVersion[$resVarName]['id']] = $execVal;
                    $this->h()->log->setTraceAttach("{$this->middlewareName} 对提交数据进行了预处理, 对有公式字段 `{$varNameIndexVersion[$resVarName]['id']}` 进行了结果矫正。");
                }
            }
        }
    }
}