<?php

namespace Application\Service\Extension\Helper;

use Application\Common\EventEnumV2;
use Application\Service\DB\Dictionary\Form;
use Application\Service\DB\Dictionary\FormGroup;
use Application\Service\Extension\Laminas;
use Application\Service\Extension\Helper\components\FormContentHelper as ComponentFormContentHelper;
use Application\Service\Extension\Params\Params;
use Laminas\Db\Sql\Predicate\NotIn;
use Laminas\Db\Sql\Predicate\Operator;

class FormContentHelper
{
    private string $event = '';
    private bool $isChangeStr = true;

    /**
     * 差异数据
     * @var bool
     */
    public ?array $changeData = [];
    public ?int $contentId = null;
    public ?array $postData = [];
    public ?array $postOriginData = null;
    public ?string $message = null;
    public ?string $messageTemplate = '{createdBy} {message}';

    protected ?string $unlockReason = null;

    protected string $contentType = ComponentFormContentHelper::CONTENT_TYPE_FORM;
    public function setPostData(array $data): FormContentHelper
    {
        $this->postData = $data;
        return $this;
    }

    public function setContentType(string $contentType): FormContentHelper {
        $this->contentType = $contentType;
        return $this;
    }

    public function setPostOriginData(array $data): FormContentHelper
    {
        $this->postOriginData = $data;
        return $this;
    }

    public function setEvent(string $event): FormContentHelper
    {
        $this->event = $event;
        return $this;
    }

    public function setMessage(string $message)
    {
        $this->message = $message;
        return $this;
    }

    public function setTemplate(string $template)
    {
        $this->messageTemplate = $template;
        return $this;
    }

    public function setContentId(int $id): FormContentHelper
    {
        $this->contentId = $id;
        return $this;
    }

    private function getLogContentId(): int
    {
        if ($this->contentType === ComponentFormContentHelper::CONTENT_TYPE_AE){
            $branch = $this->postData['branch'];
            return (int)(Laminas::$serviceManager->itemPatientAeContent->getOneFieldVal('id', "branch = '{$branch}'"));
        }

        return (int)$this->contentId;
    }

    public function setUnlockReason(string $reason): FormContentHelper
    {
        $this->unlockReason = $reason;
        return $this;
    }

    private function h(): SDMHelper
    {
        return SDMHelper::app();
    }

    public function setIsChangeStr(bool $isCompare)
    {
        $this->isChangeStr = $isCompare;
        return $this;
    }

    public function flush(array $content = [])
    {
        try {
            if ($this->event === 'EVENT_IMPORT') {
                return;
            }
            Laminas::$serviceManager->patientFormContentUpdatedLog->save($this->getFLushContent($content));
        } catch (\Exception $exception) {
            throw new \Exception('保存日志出错啦!!!!!' . $exception->getMessage());
        }
    }

    /**
     * 获取存储日志的内容
     * @param array $content
     * @return array
     * @throws \Exception
     */
    public function getFLushContent(array $content = []): array
    {

        $h = SDMHelper::app()->setAttributes(['content_id' => $this->contentId])->formContent->setContentType($this->contentType);

        $this->changeData = $changeData = $this->getChangeData();

        $fixedRole = ['FORM_CHECK_REPAIR','FORM_CHECK_LOCK','FORM_CHECK_SAVE','UNLOCK_SHARE_FORM_CONTENT','FORM_CONTENT_TEMP_STORAGE','LOCK_SHARE_FORM_CONTENT','EVENT_FORM_CONTENT_EDIT_BY_LOGIC_REPLY'];

        return [
            'item_id' => $content['item_id'] ?? $h->getItemId(),
            'patient_id' => $content['patient_id'] ??$h->getPatientId(),
            'form_id' => $content['form_id'] ?? $h->getFormId(),
            'sign_id' => $content['itemsig_id'] ?? $h->getSignId(),
            'checktime_id' => $content['checktime_id'] ??$h->getCheckTimeId(),
            'content_id' => $this->getLogContentId(),
            'data' => json_encode($this->postData), // 已经处理后的post数据
            'source' => Laminas::$serviceManager->identity->getPlatform() ?? 'SCRIPT',
            'event' => $this->event,
            'change_data' => $this->isChangeStr ? json_encode($changeData) : '[]',
            'change_data_str' => $this->isChangeStr ? $this->getChangeDataStr($changeData) : '[]',
            'role'=> (Laminas::$serviceManager->identity->getPlatform() == 'PC' && in_array($this->event,$fixedRole)) ? '图片审核员' : Laminas::$serviceManager->realRole->getRole($content['item_id'] ?? $h->getItemId(),$content['itemsig_id'] ?? $h->getSignId()),
            'json' => json_encode(ArrayHelper::filter([
                'behavior' => SDMHelper::app()->log->getBehavior(),
                'post' => $this->postOriginData ?: [],
                'headers' => Laminas::$app->getRequest()->getHeaders()->toArray() ?? [],
                'identity' => Laminas::$serviceManager->identity->getIdentityData() ?? [],
                'attach' => LogHelper::$attach,
                'message' => $this->getMessage(),
                'unlock_reason' => $this->unlockReason
            ])),
        ];
    }

    private function getMessage()
    {
        $message = $this->message === null ? $this->getDefaultMessage() : $this->message;

        $params = [
            'message' => $message,
            'createdBy' => Laminas::$serviceManager->identity->getRealName() ?? '系统脚本',
        ];
        $placeholders = [];
        foreach ($params as $name => $value) {
            $placeholders['{' . $name . '}'] = $value;
        }

        return strtr($this->messageTemplate, $placeholders);

    }

    private function getDefaultMessage()
    {
        $reflection = new \ReflectionClass(EventEnumV2::class);
        $constants = $reflection->getConstants();

        if (isset($constants[$this->event])) {
            return EventEnumV2::getDesc($constants[$this->event]);
        }

        return '未知的操作';
    }

    /**
     * 常规识别异常值判断处理
     */
    private function parseChildData(array &$data)
    {
        if (isset($data['childData'])) {
            if (!is_array($data['childData'])) {
                $childData = StringHelper::jsonDecode($data['childData']);
                foreach ($childData as $field => $item) {
                    $data[$field . '-normal-type'] = $item['normal_type'];
                }
            }
        }
    }

    /**
     * @throws \Exception
     */
    private function getChangeData()
    {
        $postData = $this->postData;

        $lastPostData = [];

        // 有可能是新增数据
        if (isset($this->postOriginData['old_data_str']) && $this->postOriginData['old_data_str']) {
            $lastPostData = StringHelper::jsonDecode($this->postOriginData['old_data_str']);
        }
        if ($lastPostData === [] && $this->contentId) {
            $old_data_where = [
                'is_del' => 0,
                'form_id' => $postData['form_id'],
            ];
            if(!empty($this->contentId)){
                $old_data_where['content_id'] = $this->getLogContentId();
            }
            if(in_array($this->event,['FORM_CHECK_SAVE','FORM_CHECK_LOCK','FORM_CHECK_UNLOCK','FORM_CHECK_REPAIR'])){
                if(in_array($this->event,['FORM_CHECK_SAVE','FORM_CHECK_LOCK','FORM_CHECK_UNLOCK','FORM_CHECK_REPAIR'])){
                    $old_data_where['event'] = ["FORM_CHECK_LOCK","FORM_CHECK_UNLOCK","FORM_CHECK_SAVE","FORM_CHECK_REPAIR"];
                }else{
                    $old_data_where[] = new Operator('id',Operator::OP_LT,0);
                }
            }else{
                $old_data_where[] = new NotIn('event', ["FORM_CHECK_SAVE","FORM_CHECK_LOCK","FORM_CHECK_UNLOCK","FORM_CHECK_REPAIR"]);
            }
            $query = Laminas::$serviceManager->patientFormContentUpdatedLog->fetchOne([
                    'order' => ['id DESC'],
                    'where' => $old_data_where
                ]) ?? null;
            if ($query) {
                $lastPostData = StringHelper::jsonDecode($query['data']);
                $lastPostData['id'] = $query['content_id'];
            }
        }

        if ($this->event == EventEnumV2::getVal(EventEnumV2::EVENT_FORM_CONTENT_EDIT_BY_LOGIC_REPLY)) {
            $this->parseChildData($postData);
            $this->parseChildData($lastPostData);
        }

        if (!$lastPostData && $this->contentId) {
            $this->h()->log->setTraceAttach('未发现历史数据。所以无法获取数据对比可能不对。');
        }

        // 非OCR表单移除手动填写
        if (
            !in_array($this->event,['FORM_CHECK_SAVE','FORM_CHECK_LOCK','FORM_CHECK_UNLOCK','FORM_CHECK_REPAIR'])
            && $this->contentId
            && $this->h()->formContent->setAttributes(['contentId' => $this->contentId])->setContentType($this->contentType)->getFormGroupId() != FormGroup::CHECK_OCR
        ) {
            unset($postData[Form::ATTACH_SDTX]);
            unset($lastPostData[Form::ATTACH_SDTX]);
        }

        if (!$postData) {
            $diffVal = ArrayHelper::diff($lastPostData, $postData);// array_diff_uassoc($lastPostData, $postData, $func);
        } else {
            $diffVal = ArrayHelper::diff($postData, $lastPostData);
        }

        foreach ($diffVal as $k => &$v) {
            if($k == 'sdtx'){
                $sdtx = json_decode($postData[$k],true);
                if($sdtx['check_date'] != $lastPostData[$k]['check_date']){
                    $originDiff['check_date'] = $lastPostData[$k]['check_date'];
                    $currentDiff['check_date'] = $sdtx['check_date'];
                }

                foreach($sdtx['content'] as $key=>$value){
                    $checkDiffVal = ArrayHelper::diff($value, isset($lastPostData[$k]['content'][$key]) ? $lastPostData[$k]['content'][$key] : []);
                    if(!empty($checkDiffVal)){
                        $originDiff[$key]['check_item'] = isset($lastPostData[$k]['content'][$key]['check_item']) ? $lastPostData[$k]['content'][$key]['check_item'] : '';
                        $originDiff[$key]['id'] = isset($lastPostData[$k]['content'][$key]['id']) ? $lastPostData[$k]['content'][$key]['id'] : '';
                        $currentDiff[$key]['check_item'] = $value['check_item'];
                        $currentDiff[$key]['id'] = $value['id'];
                        foreach($checkDiffVal as $diffK => $diffV){
                            $originDiff[$key][$diffK] = isset($lastPostData[$k]['content'][$key][$diffK]) ? $lastPostData[$k]['content'][$key][$diffK] : '';
                            $currentDiff[$key][$diffK] = $value[$diffK];
                        }
//                        $originDiff[$key] = $lastPostData[$k]['content'][$key];
                    }
                }
                $v = [
                    'origin' => $originDiff ?? [],
                    'current' => $currentDiff ?? [],
                ];
                continue;
            }
            // 非字段值就不对比了
            if ((!DataHelper::isField($k) && stripos($k, 'normal-type') === false && $k !== 'share_img') && !in_array($this->event,['FORM_CHECK_SAVE','FORM_CHECK_LOCK','FORM_CHECK_UNLOCK','FORM_CHECK_REPAIR'])) {
                unset($diffVal[$k]);
            }
            // 常规类识别 预判CS/AE 非字段值就不对比了
            if (!DataHelper::isField($k) && $this->event == 'FORM_CONTENT_TEMP_STORAGE' && $k != 'childData') {
                unset($diffVal[$k]);
            }
            $diffKey = $k;
            if(in_array($this->event,['FORM_CHECK_SAVE','FORM_CHECK_LOCK','FORM_CHECK_UNLOCK','FORM_CHECK_REPAIR'])){
                if(strpos($diffKey,'check_') !== false){
                    $diffKey = str_replace('check_','',$diffKey);
                }
                if(!in_array($diffKey,['collect_date']) && !is_numeric($diffKey)){
                    unset($diffVal[$k]);
                }
            }
            // 旧数据是array, post是string
            if (isset($lastPostData[$k]) && !is_numeric($lastPostData[$k])) {
                // 说明是json字符串
                $isJson = StringHelper::jsonDecode($postData[$k] ?? null, false);
                if ($isJson && is_array($isJson) && is_array($lastPostData[$k])) {
                    if (in_array($this->event,['FORM_CHECK_SAVE','FORM_CHECK_LOCK','FORM_CHECK_UNLOCK','FORM_CHECK_REPAIR'])) {
                        $checkDiffVal = ArrayHelper::diff($postData[$k], $lastPostData[$k]);
                        if(!empty($checkDiffVal)){
                            $originDiff = $currentDiff = [];
                            foreach ($checkDiffVal as $fieldName => $fieldValue) {
                                //if(in_array($fieldName,['id','checkname_id','item_name','unit','result','reference_range_min','min_symbol','max_symbol','reference_range_max','lock_state_small','is_normal_type'])){
                                    $originDiff[$fieldName] = $lastPostData[$k][$fieldName];
                                    $currentDiff[$fieldName] = $fieldValue;
                                //}
                            }
                            $v = [
                                'origin' => $originDiff ?? [],
                                'current' => $currentDiff ?? [],
                            ];
                        }
                        continue;
                    } else {
                        $postData[$k] = $isJson;
                        if ($lastPostData[$k] === $postData[$k]) {
                            unset($diffVal[$k]);
                            continue;
                        }
                    }
                }
            }

            $v = [
                'origin' => $lastPostData[$k] ?? null,
                'current' => $postData[$k] ?? null,
            ];
        }
        return $diffVal;
    }

    private function getChangeDataStr($changeData)
    {
        $h = SDMHelper::app()->form->field;
        $res = [];
        $checkNameArr = $checkFieldArr = [];
        if (in_array($this->event, ['FORM_CHECK_SAVE', 'FORM_CHECK_LOCK', 'FORM_CHECK_UNLOCK','FORM_CHECK_REPAIR'])) {
            $checkNameArr = Laminas::$serviceManager->dictionaryCheckname->fetchCol('name','is_del = 0');
            $checkFieldArr = Laminas::$serviceManager->patientFormContentUpdatedLog->getCheckFieldArr();
        }

        foreach ($changeData as $k => $v) {
            if ($v['origin'] === null && $v['current'] === '') {
                continue;
            }
            $change_str = '';
            $change_field = '';
            if($v['origin'] === null){
                if (in_array($this->event, ['FORM_CHECK_SAVE', 'FORM_CHECK_LOCK', 'FORM_CHECK_UNLOCK','FORM_CHECK_REPAIR'])) {
                    if($k == 'collect_date'){
                        $change_field = '采集时间';
                        $change_str = '（未填写） => '.$v['current'];
                    }
                    if(strpos($k,'check_') !== false){
                        $checkname_id = intval(str_replace('check_','',$k));
                        $change_field = isset($checkNameArr[$checkname_id]) && !empty($checkNameArr[$checkname_id]) ? $checkNameArr[$checkname_id] : '字段ID无法对应';
                        $change_str = '';
                        foreach($v['current'] as $vCurrentKey=>$vCurrentVal){
                            $vCurrentFieldArr = isset($checkFieldArr[$vCurrentKey]) && !empty($checkFieldArr[$vCurrentKey]) ? $checkFieldArr[$vCurrentKey] : [];
                            if(!empty($vCurrentFieldArr)){
                                $change_str .= $vCurrentFieldArr['name'].'【（未填写） => ';
                                //文本
                                if($vCurrentFieldArr['type'] == 0){
                                    $change_str .= $vCurrentVal.'】，';
                                }
                                //单选
                                if($vCurrentFieldArr['type'] == 1){
                                    $vCurrentVal_name = isset($vCurrentFieldArr['select']) && isset($vCurrentFieldArr['select'][$vCurrentVal]) && $vCurrentFieldArr['select'][$vCurrentVal] != '' ? $vCurrentFieldArr['select'][$vCurrentVal] : '';
                                    $change_str .= $vCurrentVal_name.'】，';
                                    unset($vCurrentVal_name);
                                }
                            }
                            unset($vCurrentFieldArr);
                        }
                        $change_str = trim($change_str,'，');
                    }
                }else{
                    $change_field = $h->getName($k);
                    $originData = '（未填写）';
                    $currentData = $h->getValueLabel($v['current'], $k);
                    $change_str = (is_array($originData) ? json_encode($originData) : $originData) . ' => ' . (is_array($currentData) ? json_encode($currentData) : $currentData);
                }
            }else{
                if (in_array($this->event, ['FORM_CHECK_SAVE', 'FORM_CHECK_LOCK', 'FORM_CHECK_UNLOCK','FORM_CHECK_REPAIR'])) {
                    if($k == 'collect_date'){
                        $change_field = '采集时间';
                        $change_str = $v['origin'].' => '.$v['current'];
                    }
                    if(strpos($k,'check_') !== false){
                        $checkname_id = intval(str_replace('check_','',$k));
                        $change_field = isset($checkNameArr[$checkname_id]) && !empty($checkNameArr[$checkname_id]) ? $checkNameArr[$checkname_id] : '字段ID无法对应';
                        $change_str = '';
                        foreach($v['current'] as $vCurrentKey=>$vCurrentVal){
                            $vCurrentFieldArr = isset($checkFieldArr[$vCurrentKey]) && !empty($checkFieldArr[$vCurrentKey]) ? $checkFieldArr[$vCurrentKey] : [];
                            if(!empty($vCurrentFieldArr)){
                                $change_str .= $vCurrentFieldArr['name'].'【';
                                //文本
                                if($vCurrentFieldArr['type'] == 0){
                                    $change_str .= $v['origin'][$vCurrentKey].' => '.$vCurrentVal.'】，';
                                }
                                //单选
                                if($vCurrentFieldArr['type'] == 1){
                                    $old_vCurrentVal_name = isset($vCurrentFieldArr['select']) && isset($vCurrentFieldArr['select'][$v['origin'][$vCurrentKey]]) && $vCurrentFieldArr['select'][$v['origin'][$vCurrentKey]] != '' ? $vCurrentFieldArr['select'][$v['origin'][$vCurrentKey]] : '';
                                    $vCurrentVal_name = isset($vCurrentFieldArr['select']) && isset($vCurrentFieldArr['select'][$vCurrentVal]) && $vCurrentFieldArr['select'][$vCurrentVal] != '' ? $vCurrentFieldArr['select'][$vCurrentVal] : '';
                                    $change_str .= $old_vCurrentVal_name.' => '.$vCurrentVal_name.'】，';
                                    unset($old_vCurrentVal_name);
                                    unset($vCurrentVal_name);
                                }
                            }
                            unset($vCurrentFieldArr);
                        }
                        $change_str = trim($change_str,'，');
                    }
                }else{
                    $change_field = stripos($k, 'normal-type') !== false ? ($h->getName(DataHelper::getFieldId($k)) . '异常值判断') : $h->getName(DataHelper::getFieldId($k));
                    $originData = $h->getValueLabel($v['origin'], $k);
                    $currentData = $h->getValueLabel($v['current'], $k);
                    $change_str = (is_array($originData) ? json_encode($originData) : $originData) . ' => ' . (is_array($currentData) ? json_encode($currentData) : $currentData);
                }
            }
            $res[] = $change_field.'：'.$change_str;

        }

        return implode('</br>', $res);
    }

    /**
     * 用来对比表单字段的值，返回对比结果
     * @param array $old
     * @param array $new
     * @return array|mixed
     */
    public function compareValue(array $old, array $new)
    {
      $diffVal = ArrayHelper::diff($new, $old);

      foreach ($diffVal as $k => &$v) {
        // 非字段值就不对比了
        if (!DataHelper::isField($k)) {
            unset($diffVal[$k]);
        }

        // 旧数据是array, post是string
        if (isset($lastPostData[$k]) && !is_numeric($lastPostData[$k])) {
            // 说明是json字符串
            $isJson = StringHelper::jsonDecode($new[$k] ?? null, false);
            if ($isJson) {
                $current[$k] = $isJson;
                if ($lastPostData[$k] === $current[$k]) {
                    unset($diffVal[$k]);
                    continue;
                }
            }
        }

            $v = [
                'origin' => $lastPostData[$k] ?? null,
                'current' => $new[$k] ?? null,
            ];
        }

      return [$diffVal, $this->getChangeDataStr($diffVal)];
    }
}