<?php

namespace Application\Service\Logic\form;

use Application\Service\DB\Dictionary\FormField;
use Application\Service\Extension\Helper\ArrayHelper;
use Application\Service\Extension\Laminas;

/**
 * 表单结构缓存生成器
 * ```
 *  $generator = new FormStructCacheGenerator;
 *  $generator->formId = 1; // 设置表单id
 *  $generator->isDictionary = false; // 希望生成字典项数据写true
 *  $generator->execute(); // 生成出序列化后的缓存数据
 * ```
 * @author toom1996
 */
class FormStructGenerator
{
    /**
     * 表单id
     * @var int|null
     */
    public ?int $formId = null;

    /**
     * 是否是字典项
     * @var bool
     */
    public bool $isDictionary = false;

    /**
     * 返回格式
     * @var bool
     */
    public bool $isArray = false;

    /**
     * @var array
     */
    private array $_fields = [];

    /**
     * @var array
     */
    private array $_fieldsTree = [];

    /**
     * 执行并返回表单及相关字段配置的数组
     *
     * 此方法组装并返回一个包含表单配置、字段配置以及处理好关联关系的字段配置的数组
     * 它不接受任何参数，也不返回错误或异常情况下的特殊值
     *
     * @return array|string 包含以下键的数组:
     *         - 'form' 表单配置
     *         - 'fields' 字段配置
     *         - 'fields_tree' 处理好关联关系的字段配置
     * @throws \Exception
     */
    public function execute()
    {
        // 返回一个数组，包含表单配置、字段配置以及处理好关联关系的字段配置
        $r = [
            'form' => $this->_getForm(), // 表单配置
            'fields' => $this->_getFields(), // 字段配置
            'fields_tree' => $this->_getFieldsTree(), // 处理好关联关系的字段配置
            'cached_at' => time(), // 缓存时间
        ];

        return $this->isArray === true ? $r : serialize($r);
    }

    /**
     * 返回表单配置所有的字段
     * @return array|mixed|
     * @throws \Exception
     */
    private function _getForm()
    {
        $query = Laminas::$serviceManager->itemForm->find($this->formId);
        if (!$query) {
            throw new \Exception('表单不存在。');
        }

        return $query;
    }

    /**
     * 获取表单字段所有的字段。
     * @return array|null
     */
    private function _getFields(): array
    {
        $this->_fields = ArrayHelper::index($this->_getFormField()->fetchAll([
            'where' => [
                'is_del' => 0,
                'form_id' => $this->formId
            ]
        ]) ?: [], 'id');

        foreach ($this->_fields as &$item) {
            $item = ArrayHelper::merge($item, $this->_getAppend($item['id']));
        }

        return $this->_fields;
    }

    /**
     * 处理字段配置。
     * @return array
     * @throws \Exception
     */
    private function _getFieldsTree()
    {
        $this->_buildTree();

        return $this->_fieldsTree;
    }

    /**
     * @throws \Exception
     */
    private function _buildTree(): void
    {
        foreach ($this->_fields as $value) {
            // 无父级字段
            if (!$value['parent']) {
                unset($value['origin_form_id']);
                $this->_fieldsTree[$value['id']] = $value;
            } else {
                $this->_fieldsTree[$value['parent']]['children'][$value['id']] = [
                    'id' => $value['id'],
                    'name' => $value['name'],
                    'order' => $value['order'] ?: 0,
                    'parent' => $value['parent'],
                    'var_name' => $value['var_name'],
                    'is_score' => $value['is_score'],
                    'score' => $value['score'],
                    'value' => $value['value'],
                    'is_check' => $value['is_check'],
                    'relation_classification' => $value['relation_classification'],
                    'relation_information' => $value['relation_information'],
                ];
            }
        }

        foreach ($this->_fieldsTree as &$item) {
            // 处理children 数据。
            // 把是否是分值和关联关系啥的都设置上
            if ((isset($item['children']) && is_array($item['children']) && isset($item['type']))) {

                // 排序
                $item['children'] = $this->orderField($item['children']);
            }
        }

        // 处理父集排序
        $field = $this->orderField($this->_fieldsTree);
        serialize($field);
    }

    /**
     * 获取表配置
     * @return FormField|\Application\Service\DB\Dictionary\ItemFormField|mixed
     */
    private function _getFormField()
    {
        if ($this->isDictionary === true) {
            return Laminas::$serviceManager->dictionaryFormField;
        }

        return Laminas::$serviceManager->itemFormField;
    }

    /**
     * 获取字段配置
     * @param $fieldId
     * @return array
     * @throws \Exception
     */
    private function _getAppend($fieldId): array
    {
        $isRadio = $this->_fields[$fieldId]['type'] == '0' && $this->_fields[$fieldId]['parent'];

        if ($isRadio === true) {
            $data = $this->_getRadio()->fetchOne(['where' => ['field_id' => $fieldId]]);
            return [
                'value' => $data['value'],
                'is_check' => $data['is_check'],
                'relation_classification' => $data['relation_classification'], // 关联的是字段还是表单
                'relation_information' => stripos($data['relation_information'], ',') !== false ? explode(',', $data['relation_information']) : ($data['relation_information'] ? [$data['relation_information']] : []), // 关联的哪个表单或者字段
                'score' => $data['score'],
                'is_score' => $data['is_score']
            ];
        } else {
            $data = $this->_getText()->fetchOne(['where' => ['field_id' => $fieldId]]);
            return [
                'tips' => $data['tips'],
                'placeholder' => $data['placeholder']
            ];
        }
    }

    /**
     * 获取表配置
     * @return FormField|\Application\Service\DB\Dictionary\ItemFormFieldRadio|mixed
     */
    private function _getRadio()
    {
        return $this->isDictionary === true ? Laminas::$serviceManager->dictionaryFormFieldRadio : Laminas::$serviceManager->itemFormFieldRadio;
    }

    /**
     * 获取表配置
     * @return FormField|\Application\Service\DB\Dictionary\ItemFormFieldRadio|mixed
     */
    private function _getText()
    {
        return $this->isDictionary === true ? Laminas::$serviceManager->dictionaryFormFieldText : Laminas::$serviceManager->itemFormFieldText;
    }

    /**
     * 排序
     * @param array $field
     * @return array
     */
    protected function orderField(array $field)
    {
        ArrayHelper::multisort($field, 'order');
        return array_column($field, null, 'id');
    }
}