<?php

namespace Application\Service\Extension\Xml;

use Application\Service\DB\Dictionary\Form;
use Application\Service\DB\Dictionary\FormGroup;
use Application\Service\DB\Dictionary\ItemForm;
use Application\Service\Exceptions\InvalidArgumentException;
use Application\Service\Extension\Helper\ArrayHelper;
use Application\Service\Extension\Helper\StringHelper;
use Application\Service\Extension\Helper\SyncPatientHelper;
use Application\Service\Extension\Laminas;
use Application\Service\Extension\Xml\exceptions\InvalidDataException;
use Laminas\Validator\Uuid;

class FormContentXmlGenerator extends BaseXmlGenerator
{
    /**
     * 表单id
     * @var int|null
     */
    public ?int $formId = 0;

    /**
     * 项目id
     * @var int|null
     */
    public ?int $itemId = 0;

    /**
     * 受试者id
     * @var int|null
     */
    public ?int $patientId = 0;

    /**
     * 中心id
     * @var string|null
     */
    public ?string $itemSignId = '0';

    /**
     * 中心编号
     * @var string|null
     */
    public ?string $itemSignIdNumber = '0';

    /**
     * 检查点id
     * @var int|null
     */
    public ?int $checkTimeId = 0;

    public int $recordId = 0;

    public array $syncField = [];

    protected array $recordData = [];

    protected array $patientData = [];

    private array $formData = [];

    public array $formContent = [];

    private array $versionData = [];

    /**
     * 已经同步过的贯穿全程类的表单id.
     * @var array
     */
    public static array $processArray = [];

    /**
     * 当前渲染的数据是否要写成删除
     * @var bool
     */
    private bool $isDeleteItemData = false;

    public int $deleteMultiId = 0;

    /** @var bool 当前id是否已经被删除 */
    public bool $isDeletedMultiId = false;

    public array $multiId = [];

    private ?\Closure $ocrRecord = null;

    public const TRANSACTION_TYPE_INSERT = 'Insert';
    public const TRANSACTION_TYPE_UPDATE = 'Update';
    public const TRANSACTION_TYPE_DELETE = 'Delete';

    public const SYNC_TYPE_PATIENT = 1;

    public const SYNC_TYPE_FORM_CONTENT= 2;

    protected function getPatientData()
    {
        if (!$this->patientData) {
            $this->patientData = Laminas::$serviceManager->patient->fetchOne([
                'columns' => ['patient_number', 'id', 'patient_content'],
                'where' => ['id' => $this->patientId, 'is_del' => 0]
            ]);
            $this->patientData['patient_content'] = ArrayHelper::index(json_decode($this->patientData['patient_content'], true), 'field');
        }

        if (!$this->patientData) {
            throw new InvalidDataException("受试者{$this->patientId}参数不正确。");
        }

        return $this->patientData;
    }

    public function getFormData()
    {
        if (!$this->formData) {
            $this->formData = Laminas::$serviceManager->itemForm->fetchOne([
                'where' => ['id' => $this->formId]
            ]);

            if (!$this->formData) {
                throw new InvalidArgumentException('formId 有问题。');
            }
        }

        return $this->formData;
    }

    public function getFormContent(string $fetchMode = 'fetchOne', bool $throwException = true)
    {
        if (!$this->formContent) {
            $table = 'patientFormContent';
            $where = [
                'patient_id' => $this->patientId,
                'item_id' => $this->itemId,
                'form_id' => $this->formId,
                'checktime_id' => $this->checkTimeId
            ];

            $type = $this->getFormData()['group_id'];

            if ($this->checkTimeId == 99) {
                if ($type == FormGroup::THROUGH_PROCESS) {
                    unset($where['checktime_id']);
                }

                if ($type == FormGroup::AE) {
                    $table = 'itemPatientAeContent';
                    $resStatus = [];
                    $resultArr = Laminas::$serviceManager->itemCsaeRelation->fetchAll([
                        'where' => ['patient_id' => $this->patientId]
                    ]);

                    foreach ($resultArr as $v) {
                        $resStatus[$v['content_id']] = $v['is_del'];
                    }

                    if ($resultArr && is_array($resultArr)) {
                        $where['id'] = ArrayHelper::getColumn($resultArr, 'content_id');
                    } else {
                        $where['id'] = 'aaaaaaa'; // 找不到数据就行
                    }
                    unset($where['checktime_id']);
                    unset($where['form_id']);
                }

                if ($type == FormGroup::SAE) {
                    $table = 'itemPatientAeContent';
                    unset($where['checktime_id']);
                }

                if ($type == FormGroup::TEST_SUMMARY) {
                    $table = 'itemPatientAeContent';
                    unset($where['checktime_id']);
                }
            }

            $this->formContent = Laminas::$serviceManager->$table->$fetchMode([
                'where' => $where
            ]) ?: [];

            // ae数据矫正
            if ($table == 'itemPatientAeContent') {
                foreach ($this->formContent as &$content) {
                    $content['is_del'] = $resStatus[$content['id']] ?? $content['is_del'];
                }
            }
//            var_dump($resStatus);
//            var_dump($this->formContent);die;
            if (!$this->formContent) {
                if ($throwException === false) {
                    return false;
                }
                throw new InvalidArgumentException('未找到填写的表单数据??');
            }
        }

        return $this->formContent;
    }

    protected function getRecordData(int $itemGroupRepeatKey = 0)
    {
        $where = [
            'sync_type' => self::SYNC_TYPE_FORM_CONTENT,
            'patient_id' => $this->patientId,
            'item_id' => $this->itemId,
            'item_sign_id' => $this->itemSignId,
            'form_id' => $this->formId,
            'checktime_id' => $this->checkTimeId
        ];

        if ($itemGroupRepeatKey) {
            $where['multi_id'] = $itemGroupRepeatKey;
        }

        $recordData = Laminas::$serviceManager->odmSyncRecord->fetchOne([
            'columns' => ['id', 'sync_field', 'is_del'],
            'where' => $where
        ]);

        if ($itemGroupRepeatKey && !$recordData) {
            $this->recordData = [];
            $this->recordId = 0;
        }

        if ($recordData) {
            $this->recordData = json_decode($recordData['sync_field'], true);
            $this->recordId = $recordData['id'];
            $this->isDeletedMultiId = (bool)$recordData['is_del'];
//            var_dump($itemGroupRepeatKey);
//            var_dump($this->isDeletedMultiId);die;
        }

        return $this->recordData;
    }

    protected function getVersionData()
    {
        if (!$this->versionData) {
            $this->versionData = Laminas::$serviceManager->itemFormVersion->getField(['form_id' => $this->formId], true);

            if (!$this->versionData) {
                throw new InvalidArgumentException('找不到version数据??');
            }
        }

        return $this->versionData;
    }

    protected function getOcrXml()
    {
        $where = [
            'item_id' => $this->itemId,
            'checktime_id' => $this->checkTimeId,
            'itemsig_id' => $this->itemSignId,
            'patient_form_id' => call_user_func(function () {
                return Laminas::$serviceManager->patientForm->fetchOne(['where' => [
                    'form_id' => $this->formId,
                    'item_id' => $this->itemId,
                    'patient_id' => $this->patientId,
                    'itemsig_id' => $this->itemSignId,
                    'checktime_id' => $this->checkTimeId,
                ]])['id'] ?? 0;
            }),
            'patient_id' => $this->patientId,
            'category_id' => $this->getFormData()['checklist_id'],
            'form_id' => $this->formId,
            'type' => $this->getFormContent()['is_yc'] == 1 ? '1' : '2',
        ];
//var_dump($where);die;
        $arrayContainer = Laminas::$serviceManager->itemIdentificationresultchange->sendChangLockData($where);
        $xmlArray = $arrayContainer->generate();
        $this->ocrRecord = function () use ($where) {
            Laminas::$serviceManager->itemIdentificationresultchange->insertItemChangesendlog($where);
        };
        $this->multiId = $arrayContainer->multiId;
        $this->syncField = array_unique($arrayContainer->syncField);
        return $xmlArray;
    }

    public function saveOcrRecord()
    {
        if ($this->ocrRecord) {
            call_user_func($this->ocrRecord);
        }
    }

    private function getItemSignIdNumber()
    {
        if (!$this->itemSignIdNumber) {
            $query = Laminas::$serviceManager->itemSignatory->fetchOne([
                'where' => ['id' => $this->itemSignId]
            ])['number'] ?? false;

            if (!$query) {
                throw new InvalidArgumentException('未发现正确的中心编号??');
            }

            $this->itemSignIdNumber = $query;
        }

        return $this->itemSignIdNumber;
    }

    public function generate(): array
    {
//        $this->getRecordData();

        $formData = $this->getFormData();

        if ($formData['group_id'] == FormGroup::CHECK_OCR) {
            $generateData = $this->getOcrXml();
        } else {
            $clinicalDataTag = $this->buildClinicalDataTag($this->getClinicalDataAttributes());

            $subjectDataTag = $this->buildSubjectDataTag($this->getSubjectDataAttributes());

            $studyEventData = $this->buildStudyEventDataTag($this->getStudyEventDataAttributes());

            $formData = $this->buildFormDataDataTag($this->getFormDataAttributes());

            $siteRefTag = $this->buildSiteRefDataTag($this->getLocationRefDataAttributes());

            $generateData = [
                $clinicalDataTag => [
                    $subjectDataTag => [
                        $siteRefTag => [],
                        $studyEventData => [
                            $formData => call_user_func(function () {
                                return $this->getGroupData();
                            }),
                        ]
                    ]
                ]
            ];
        }

        if ($this->getFormData()['group_id'] == FormGroup::THROUGH_PROCESS) {
            $this->setProcessSync($this->formId);
        }

        return $generateData;
    }

    protected function getClinicalDataAttributes(): array
    {
        return [
            'StudyOID' => $this->getStudyOID(),
            'MetaDataVersionOID' => $this->getMetaDataVersionOID(),
            'HLT:Environment' => 'test'
        ];
    }

    protected function getSubjectDataAttributes(): array
    {
        $res = [];

        if ($this->getPatientData()['patient_number']) {
            $res['SubjectKey'] = $this->getPatientData()['patient_number'];
        }

        $res['TransactionType'] = self::TRANSACTION_TYPE_UPDATE;// SyncPatientHelper::getIsSync($this->patientId) ? self::TRANSACTION_TYPE_UPDATE : self::TRANSACTION_TYPE_INSERT;

        return $res;
    }

    protected function getStudyEventDataAttributes(): array
    {
        return [
            'StudyEventOID' => $this->checkTimeId,
            'TransactionType' => self::TRANSACTION_TYPE_UPDATE
        ];
    }

    protected function getFormDataAttributes(): array
    {
        return [
            'FormOID' => $this->getFormData()['var_name'],
            'TransactionType' => 'Update',
        ];
    }

    private function getItemDataAttributes(array $item = []): array
    {
        return [
            'value' => $item['value'],
            'ItemOID' => $item['var_name'],
            'TransactionType' => $item['value']
        ];
    }

    protected function getItemGroupDataAttributes(int $itemGroupRepeatKey = 0, $isDelete = false)
    {
        $formData = $this->getFormData();

        $groupTransactionType = self::TRANSACTION_TYPE_UPDATE;

        if ($this->deleteMultiId !== 0 && $this->isDeleteItemData === true) {
            $groupTransactionType = self::TRANSACTION_TYPE_DELETE;
            $this->isDeleteItemData = true;
        }

        $res = [
            'ItemGroupOID' => $this->getFormData()['var_name'],
            'TransactionType' => $groupTransactionType
        ];

        $this->getRecordData($itemGroupRepeatKey);

        // 一对多需要设置 ItemGroupRepeatKey
        if ($formData['type'] == Form::FORM_TYPE_MULTI) {
            $res['ItemGroupRepeatKey'] = $itemGroupRepeatKey;
            $res['TransactionType'] = $this->isDeleteItemData === true ? self::TRANSACTION_TYPE_DELETE : ($this->recordData ? self::TRANSACTION_TYPE_UPDATE : self::TRANSACTION_TYPE_INSERT);
        }

        return $res;
    }

    protected function getLocationRefDataAttributes()
    {
        return [
            'LocationOID' => $this->getItemSignIdNumber(), // $this->itemSignId
        ];
    }

    /**
     * @param string $data
     * @return array
     */
    protected function getItemData(string $data = '')
    {
//        $formData = $this->getFormData();

        // 一对一
//        if ($formData['type'] == Form::FORM_TYPE_SINGLE) {
        //        }
//        elseif ($formData['type'] == Form::FORM_TYPE_MULTI) {
//            $data = $this->buildMultiFormItemData();
//        }

        return $this->buildSingleFormItemData($data);
    }

    private function getStudyOID(): string
    {
        // ZYYY-LC-20211001 干细胞治疗失代偿期肝硬化患者的耐受性、安全性和有效性的探索性临床研究
        // 20211129 评估注射用胶原酶治疗颈椎间盘突出症的有效性和安全性：一项探索性、单臂、开放、多中心试验
        return 'C2040001';
    }

    private function getVarName(string $key, string $originKey, $implodeMode = false)
    {
        if ($originKey == 'score') {
            $field = 'SCORE_' . $this->getFormData()['var_name'];
            $this->syncField[] = $field;
            return $field;
        }

        $versionData = $this->getVersionData();

        if (isset($versionData[$key])) {
            if ($implodeMode === true && stripos($originKey, '-') !== false) {
                $ex = explode('-', $originKey);
                array_shift($ex);

                $fieldData = $versionData[$ex[0]];
                $fieldDataVarName = $fieldData['var_name'] ?? '';

                $radioData = ArrayHelper::index($fieldData['children'], 'value');
                $radioDataVarName = $radioData[$ex[1]]['var_name'] ?? '';
                $r = ("{$fieldDataVarName}_{$versionData[$key]['var_name']}");

            } else {
                $r = $versionData[$key]['var_name'];
            }

        } else {
            $getVarName = function (string $key) use ($versionData) {
                foreach ($versionData as $item) {
                    if (in_array($key, $item['children_list'])) {
                        return $item['var_name'];
                    }
                }

                return null;
            };

            $r = $getVarName($key);

            if (!$r) {

                return 'UNKNOWN';
                $originId = Laminas::$serviceManager->itemFormField->fetchOne(['where' => ['id' => $key]])['origin_form_id'] ?? false;

                if (!$originId) {
                    throw new InvalidArgumentException('无法取到当前字段变量名呀');
                }

                $varName = Laminas::$serviceManager->itemFormField->fetchOne(['where' => ['id' => $originId]])['var_name'] ?? false;

                if (!$varName) {
                    throw new InvalidArgumentException('无法通过origin_form_id 获取变量名');
                }

                $r = $varName;
            }
        }

        // 存储同步的字段
        $this->syncField[] = $r;

        return $r;
    }

    /**
     * 提交模式
     * @param array $rowData
     * @return bool
     */
    private function getMode(array $rowData): bool
    {
        $tmp = [];
        foreach ($rowData as $fieldKey => $data) {
            if (stripos($fieldKey, '-') !== false) {
                $firstKey = explode('-', $fieldKey)[0];
                if (!in_array($firstKey, $tmp)) {
                    $tmp[] = $firstKey;
                } else {
                    return true;
                }
            }
        }

        return false;
    }

    protected function buildSingleFormItemData(string $data = '')
    {
        $rowData = $data;

        if (!$rowData) {
            $rowData = $this->getFormContent()['data'];
        }

        $versionData = $this->getVersionData();

        $rowData = StringHelper::jsonDecode($rowData, true);

        $mode = $this->getMode($rowData);

        $data = $tmp = [];

        // 提交过来的表单数据
        foreach ($rowData as $key => $item) {
            // 对分值特殊处理
            if ((is_numeric($key) || stripos($key, '-') !== false) || $key == 'score') {
                $fieldId = explode('-', $key)[0];
                // 用来存储和提交过来的数据做比对用的临时变量
                $itemOid = $this->getVarName($fieldId, $key, $mode);
                $tmp[] = $fieldId;
                // 体格检查, 改完了格式不对了, 自己屏蔽了
                if (in_array($itemOid, ['UNKNOWN', 'PEDESC', 'PERES'])) {
                    continue;
                }
                $tag = $this->buildTagAttributes([
                    'ItemOID' => $itemOid,
                    'TransactionType' => $this->isDeleteItemData ? self::TRANSACTION_TYPE_DELETE : $this->getItemDataTransactionType($itemOid),
                    'Value' => call_user_func_array(function ($item) {
                        if (is_array($item)) {
                            return implode(',', $item);
                        }

                        return $item;
                    }, [$item]),
                ]);

                $data["ItemData $tag"] = [];
            }
        }

//        // 所有的表单数据
//        // 提交的时候没有, 说明就没展示, 就需要传空值过去
        foreach ($versionData as $fieldId => $v) {
            if (!in_array($fieldId, $tmp)) {
                $itemOid = $this->getVarName($fieldId, $fieldId);
                $tag = $this->buildTagAttributes([
                    'ItemOID' => $itemOid,
                    'TransactionType' => $this->isDeleteItemData ? self::TRANSACTION_TYPE_DELETE : $this->getItemDataTransactionType($itemOid),
                    'Value' => '',
                ]);

                $data["ItemData $tag"] = [];
            }
        }

        return $data;
    }

    /**
     * 上次这个数据是否同步过了, 同步过了就是UPDATE, 否则就是INSERT.
     * @param string $itemOID 变量名
     * @return string
     */
    private function getItemDataTransactionType(string $itemOID): string
    {
        $formType = $this->getFormData()['type'];

        if ($this->recordData === []) {
            return self::TRANSACTION_TYPE_INSERT;
        }

        if (!in_array($itemOID, $this->recordData)) {
            return self::TRANSACTION_TYPE_INSERT;
        }


        return self::TRANSACTION_TYPE_UPDATE;
    }

    /**
     * 这个贯穿全程类的表单此次是否同步过了.
     * @return bool
     */
    public function getIsProcessSync()
    {
        if (in_array($this->formId, self::$processArray) && $this->getFormData()['group_id'] == FormGroup::THROUGH_PROCESS) {
            return true;
        }

        return false;
    }

    /**
     * 是否需要同步
     */
    public function isSync()
    {
        $formType = $this->getFormData();

        // 非共同页
        if ($this->checkTimeId != 99) {
            if (in_array($formType['group_id'], [FormGroup::SAE, FormGroup::AE, FormGroup::THROUGH_PROCESS, FormGroup::TEST_SUMMARY])) {
                return false;
            }
        }

        // 识别类锁定了才传
        if ($formType['group_id'] == FormGroup::CHECK_OCR) {
            // 是否锁定
//            return (bool)Laminas::$serviceManager->itemPatientworkannex->fetchOne([
//                'where' => [
//                    'form_id' => $this->formId,
//                    'lock_state' => 1,
//                    'patient_id' => $this->patientId,
//                    'item_id' => $this->itemId,
//                    'checktime_id' => $this->checkTimeId,
//                    'itemsig_id' => $this->itemSignId,
//                    'is_del' => 0
//                ]
//            ]);
        }

        return true;
    }

    /**
     * 这个贯穿全程类的表单此次是否同步过了.
     * @return bool
     */
    public function setProcessSync($formId)
    {
        if (!isset(self::$processArray[$formId])) {
            self::$processArray[] = $formId;
        }
    }


    private function handleSpecialForm(int $formId): array
    {
        if ($formId == 920) {
            $data = StringHelper::jsonDecode($this->getFormContent()['data']);
            $versionData = $this->getVersionData();
            $buildConfig = Laminas::$serviceManager->itemForm->getPreviewConfig($formId, true);

//            var_dump($buildConfig);die;
            $tmp = [];
//            var_dump($data);
            $groupKey = function ($itemGroupRepeatKey) {
                $groupTransactionType = self::TRANSACTION_TYPE_UPDATE;

                $res = [
                    'ItemGroupOID' => $this->getFormData()['var_name'],
                    'TransactionType' => $groupTransactionType
                ];

//                // 一对多需要设置 ItemGroupRepeatKey
//                if ($formData['type'] == Form::FORM_TYPE_MULTI) {
//                    $res['ItemGroupRepeatKey'] = $itemGroupRepeatKey;
//                    $res['TransactionType'] = $this->getRecordData($itemGroupRepeatKey) ? self::TRANSACTION_TYPE_UPDATE : self::TRANSACTION_TYPE_INSERT;
//                }

                $res['ItemGroupRepeatKey'] = $itemGroupRepeatKey;
                $this->multiId[] = $itemGroupRepeatKey;
                return $res;
            };

            $itemData = function ($generateFields, $parent) use ($data, $versionData) {
                $arr = [];
                foreach ($generateFields as $field) {
                    if (stripos($field, '-') === false) {
                        $generateSelfFieldId = $generateParentFieldId = $field;
                    } else {
                        list ($generateSelfFieldId, $generateParentFieldId) = explode('-', $field);
                    }

                    if ($generateParentFieldId == $parent) {
                        if ($generateSelfFieldId == $generateParentFieldId) {
                            $this->syncField[] = $this->getFormData()['var_name'];
                            // 特殊处理, 需要多加一层
                            $tag = $this->buildTagAttributes([
                                'ItemOID' => $this->getFormData()['var_name'],
                                'TransactionType' => $this->getRecordData() ? self::TRANSACTION_TYPE_UPDATE : self::TRANSACTION_TYPE_INSERT,
                                'Value' => $versionData[$generateSelfFieldId]['name'],
                            ]);

                            $arr["ItemData $tag"] = [];
                        }


                        $tag = $this->buildTagAttributes([
                            'ItemOID' => $versionData[$generateSelfFieldId]['var_name'],
                            'TransactionType' => $this->getRecordData() ? self::TRANSACTION_TYPE_UPDATE : self::TRANSACTION_TYPE_INSERT,
                            'Value' => call_user_func_array(function ($item) {
                                if (is_array($item)) {
                                    return implode(',', $item);
                                }

                                return $item;
                            }, [$data[$field] ?? '']),
                        ]);
                        $this->syncField[] = $versionData[$generateSelfFieldId]['var_name'];
                        $arr["ItemData $tag"] = [];
                    }
                }

                return $arr;
            };

            $firstLevel = ArrayHelper::index($buildConfig['config']['form'], 'prop');
            foreach ($firstLevel as $key => $item) {
                $itemGroupData = $this->buildItemGroupDataTag($groupKey($key));
                $tmp[$itemGroupData] = $itemData($buildConfig['generateFields'], $key);
            }

            return $tmp;
        }
    }

    /**
     * @return array|array[]
     * @throws \Exception
     */
    protected function getGroupData(): array
    {
        // 体格检查特殊处理, 要处理成一对多的
        if ($this->getFormData()['id'] == 920) {
            return $this->handleSpecialForm(920);
        }

        $formType = $this->getFormData()['type'];

        // 一对一
        if ($formType == Form::FORM_TYPE_SINGLE) {
            $itemGroupData = $this->buildItemGroupDataTag($this->getItemGroupDataAttributes());
            return [$itemGroupData => $this->getItemData()];
        } elseif ($formType == Form::FORM_TYPE_MULTI) { // 一对多
            $arr = [];

            // 这里应该看情况改一下, 看用哪种比较合适。
            // 是指定一个id一个一个传, 还是批量传过去
            foreach ($this->getFormContent('fetchAll') as $index => $item) {
                $this->isDeleteItemData = false;
                if ($item['is_del'] == 1) {
                    $this->deleteMultiId = $item['id'];
                    $this->isDeleteItemData = true;
                }

                $itemGroupData = $this->buildItemGroupDataTag($this->getItemGroupDataAttributes($index + 1));

                if ($item['is_del'] == 1) {
//                    var_dump($this->isDeletedMultiId);die;
                    if ($this->isDeletedMultiId === true || !$this->recordData) {
                        continue;
                    }
//                    continue;
                }

                if ($item['id'] == $this->deleteMultiId) {
                    $this->isDeleteItemData = true;
                }

                $arr[$itemGroupData] = $this->getItemData($item['data']);
                $this->multiId[] = $index + 1;
                $this->isDeleteItemData = false;
            }

            return $arr;
        }

        throw new \Exception("表单类型不对啊");
    }

    private function getMetaDataVersionOID(): string
    {
        return StringHelper::generateUuid();
    }

    public function getSyncField(): array
    {
        return $this->syncField;
    }

    public function getSyncType()
    {
        return self::SYNC_TYPE_FORM_CONTENT;
    }

    public function deleteMultiId(int $id)
    {
        $this->deleteMultiId = $id;
        return $this;
    }
}
