<?php

declare(strict_types=1);

namespace app\common\arw\adjfut\src\Traits;

use think\exception\ValidateException;
use think\helper\Arr;
use think\Model;
use app\common\arw\adjfut\src\Exception\ErrorMsg;

/**
 * 字典类
 * @mixin Model
 */
trait Dictionary
{
    // /**
    //  * 字典映射
    //  *
    //  * @var array
    //  * @date 2023-01-10
    //  * @example
    //  * @author arw
    //  * @since 1.0.0
    //  */
    // public static $dictionaryMap = [];
    /**
     * 字典缓存
     *
     * @var array
     * @date 2023-01-10
     * @example
     * @author arw
     * @since 1.0.0
     */
    private static $dictionaryCache = [];
    /**
     * 获取字典模型映射
     *
     * @param string $guid
     * @return array
     * @date 2023-01-10
     * @example
     * @author arw
     * @since 1.0.0
     */
    private static function getDictionaryModelMap(string $guid): array
    {
        return [];
    }

    /**
     * 验证字典
     *
     * @param bool $ignoreNull 忽略null值
     * @param array $ignoreField 忽略字段验证
     * @return void
     * @throws ValidateException
     * @date 2023-01-11
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function validateDictionary(bool $ignoreNull = false, array $ignoreField = []): void
    {
        $map = self::getDictionaryMap();
        $errors = [];
        foreach ($map as $field => &$dictionary) {
            list($field, $title) = self::getDictionaryField($field);
            if (in_array($field, $ignoreField)) {
                continue;
            }
            $value = $this->$field;
            if (is_null($value) && $ignoreNull) {
                continue;
            }
            $dictionary = self::getDictionaryFieldMap($field);
            $keys = array_keys($dictionary);
            if (!in_array($value, $keys)) {
                $values = array_values($dictionary);
                $msg = join(',', $values);
                $errors[] = "$title 应在[ $msg ]";
            }
            unset($dictionary);
        }
        if ($errors) {
            throw new ValidateException($errors);
        }
    }

    /**
     * 获取字典值
     *
     * @param string $field 字段
     * @param mixed $value 设置器内调用无法会无法获取当前值 需要手动传入
     * @return mixed
     * @date 2023-01-11
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function getDictionaryValue(string $field, $value = null)
    {
        $map = self::getDictionaryFieldMap($field);
        if (is_null($value)) {
            $value = $this->$field;
        }
        if (isset($map[$value])) {
            return $value;
        }
        $key = array_search($value, $map);
        if ($key === false) {
            $msg = join(',', array_values($map));
            throw new ErrorMsg("$field 应在[ $msg ]", 1);
        }
        return $key;
    }

    /**
     * 获取字典名称
     *
     * @param string $field 字段
     * @param mixed $default 默认值 如果默认值在字典值内 则返回字典名称
     * @return mixed
     * @date 2023-01-11
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function getDictionaryName(string $field, $default = null)
    {
        $map = self::getDictionaryFieldMap($field);
        if (isset($map[$default])) {
            $default = $map[$default];
        }
        return Arr::get($map, $this->$field, $default);
    }

    /**
     * 获取字典名称（弃用保留兼容）
     * 请调用 getDictionaryName
     *
     * @param string $field 字段
     * @param mixed $default 默认值
     * @deprecated 1.0.0
     * @return mixed
     * @date 2023-01-10
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function getDictionaryText(string $field, $default = null)
    {
        return $this->getDictionaryName($field, $default);
    }

    /**
     * 获取字典字段映射
     *
     * @param string $field 字段
     * @return array
     * @date 2023-01-10
     * @example
     * @author arw
     * @since 1.0.0
     */
    public static function getDictionaryFieldMap(string $field): array
    {
        list($field) = self::getDictionaryField($field);
        $cache = Arr::get(self::$dictionaryCache, $field);
        if (is_array($cache)) {
            return $cache;
        }
        $map = Arr::get(self::getDictionaryMap(), $field);
        if (!$map) {
            throw new ErrorMsg("未定义字段映射", 1);
        }
        if (is_array($map)) {
            self::$dictionaryCache[$field] = $map;
            return self::$dictionaryCache[$field];
        }
        if (is_string($map)) {
            self::$dictionaryCache[$field] = self::getDictionaryModelMap($map);
            return self::$dictionaryCache[$field];
        }
        return [];
    }

    /**
     * 获取字典映射
     *
     * @return array
     * @date 2023-01-10
     * @example
     * @author arw
     * @since 1.0.0
     */
    public static function getDictionaryMap(): array
    {
        $self = new self;
        $exists = property_exists($self, 'dictionaryMap') && isset($self::$dictionaryMap);
        return $exists  ? $self::$dictionaryMap : [];
    }

    /**
     * 获取字典字段
     *
     * @param string $value
     * @return array
     * @date 2023-01-13
     * @example
     * @author arw
     * @since 1.0.0
     */
    private static function getDictionaryField(string $value): array
    {
        $temp = explode('|', $value);
        $field = Arr::get($temp, '0');
        $title = Arr::get($temp, '1', $field);
        return [$field, $title];
    }
}
