<?php

namespace Application\Service\Extension\Validator;

use Application\Service\Extension\Helper\ArrayHelper;
use Application\Service\Extension\Laminas;
use Application\Service\Extension\Validator\customer\RequiredValidator;
use Laminas\Validator\Exception\InvalidArgumentException;
use Laminas\Validator\GreaterThan;
use Laminas\Validator\LessThan;
use Laminas\Validator\Regex;
use Laminas\Validator\StringLength;

/**
 * 表单规则验证器
 * 前端验证规则 https://blog.51cto.com/u_15127687/4273155#type
 */
class FormValidator extends BaseCustomValidator
{

    public $config = '';

    public string $target = '';

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

        $configFile = null;

        $configFile = Laminas::$app->getConfig()['formValidator'][$this->config];

        if (!$configFile || !file_exists($configFile)) {
            throw new InvalidArgumentException('配置文件路径不对呀。');
        }

        $this->config = include $configFile;
        $config['fnParams'] = $config['fnParams'] ?? [];
        if(is_callable($this->config)) $this->config = ($this->config)($config['fnParams']);
        if ($this->target !== '') {
            $this->config = ArrayHelper::getValue($this->config, $this->target);
        }

    }
    /**
     * 如果未指定表单名称则使用POST
     * @param null $options 表单名称
     */
//    public function __construct(array $config)
//    {
//        parent::__construct();
//        var_dump($this);
//        $configFile = null;
//
//        $configFile = Laminas::$app->getConfig()['formValidator'][$this->config];
//
//        var_dump($configFile);
//        if (!$configFile || !file_exists($configFile)) {
//            throw new InvalidArgumentException('配置文件路径不对呀。');
//        }
//
//        $this->config = include $configFile;
//        var_dump($this->config);die;
//        if ($this->target !== '') {
//            $this->config = ArrayHelper::getValue($this->config, $this->target);
//        }
//        var_dump($this->target);die;
//    }

    /**
     * @inheritdoc
     * @param mixed $value
     * @param null $attribute
     * @return bool
     */
    public function isValid($value, $attribute = null)
    {
        $rules = $this->config[$attribute]['rules'] ?? [];

        // 没定义规则就跳过
        if (!$rules) {
            return null;
        }

        foreach ($rules as $rule) {
            $validators = $this->getValidators($rule);
            foreach ($validators as $validator) {
                if ($validator instanceof \Closure) {
                    return $validator($value, $attribute);
                }
            }
        }

        return null;
    }

    /**
     * 获取一个规则内所有的规则属性
     * @param array $rule rule `[ 'type' => 'number', 'min' => 0, 'max' => 200]`
     * @return array
     */
    public function getValidators(array $rule = []): array
    {
        $handleClass = [];

        if (isset($rule['required']) && $rule['required'] == true) {
            $handleClass[] = $this->getRequiredHandler($rule);
        }

//        if (isset($rule['min'])) {
//            $handleClass[] = $this->getMinHandler($rule);
//        }
//
//        if (isset($rule['max'])) {
//            $handleClass[] = $this->getMaxHandler($rule);
//        }
//
//        if (isset($rule['len'])) {
//            $handleClass[] = $this->getLenHandler($rule);
//        }
//
//        if (isset($rule['pattern'])) {
//            $handleClass[] = $this->getPatternHandler($rule);
//        }
//
//        if (isset($rule['enum'])) {
//            $handleClass[] = $this->getEnumHandler($rule);
//        }


        return $handleClass;
    }

    /**
     * 获取`required`处理规则
     * @param array $rule
     * @return \Closure
     */
    protected function getRequiredHandler(array $rule)
    {
        return function ($value, $attribute) use ($rule) {
            $labels = [];
            if (is_array($this->config)) {
                foreach ($this->config as $fieldName => $label) {
                    $labels[$fieldName] = $label['label'] ?? '';
                }
            }
            if ($labels) {
                $validator = new RequiredValidator([
                    'attributeLabels' => $labels,
                ]);
            } else {
                $validator = new RequiredValidator();
            }

            if ($result = $validator->isValid($value, $attribute)) {
                return $result;
            }

            return null;
        };

    }

    /**
     * 获取`min`处理规则
     * @param array $rule
     * @return \Closure
     */
    protected function getMinHandler(array $rule)
    {
        return function ($value, $attribute) use ($rule) {
            if (isset($rule['type']) && in_array($rule['type'], ['number', 'integer', 'float'])) {
                $validator = new GreaterThan([
                    'min' =>  intval($rule['min']),
                    'inclusive' => true
                ]);
                $ruleMessage = $rule['message'] ?? "{$this->config[$attribute]['label']}的值不能小于{$rule['min']}";
            }else{
                $validator = new StringLength([
                    'min' =>  intval($rule['min']),
                    'encoding' => 'UTF-8',
                ]);
                $ruleMessage = $rule['message'] ?? "{$this->config[$attribute]['label']}输入长度不能小于{$rule['min']}";
            }

            if (!$validator->isValid($value)) {
                throw new InvalidArgumentException($ruleMessage);
            }

            return true;
        };
    }

    /**
     * 获取`max`处理规则
     * @param array $rule
     * @return \Closure
     */
    protected function getMaxHandler(array $rule)
    {
        return function ($value, $attribute) use ($rule) {
            if (isset($rule['type']) && in_array($rule['type'], ['number', 'integer', 'float'])) {
                $validator = new LessThan([
                    'max' =>  intval($rule['max']),
                    'inclusive' => true
                ]);
                $ruleMessage = $rule['message'] ?? "{$this->config[$attribute]['label']}的值不能大于{$rule['max']}";
            }else{
                $validator = new StringLength([
                    'max' =>  intval($rule['max']),
                    'encoding' => 'UTF-8',
                ]);
                $ruleMessage = $rule['message'] ?? "{$this->config[$attribute]['label']}长度不能大于{$rule['max']}";
            }

            if (!$validator->isValid($value)) {
                throw new InvalidArgumentException($ruleMessage);
            }

            return true;
        };
    }

    /**
     * 获取`len`处理规则
     * @param array $rule
     * @return \Closure
     */
    protected function getLenHandler(array $rule)
    {
        return function ($value, $attribute) use ($rule) {
            if (isset($rule['type']) && in_array($rule['type'], ['number', 'integer', 'float'])) {
                if (intval($value) != intval($rule['len'])) {
                    throw new InvalidArgumentException($rule['message'] ?? "{$this->config[$attribute]['label']}必须是{$rule['len']}");
                }
            }else{
                if (mb_strlen($value) != intval($rule['len'])) {
                    throw new InvalidArgumentException($rule['message'] ?? "{$this->config[$attribute]['label']}长度必须是{$rule['len']}");
                }
            }

            return true;
        };
    }

    /**
     * 获取`pattern`处理规则
     * @param array $rule
     * @return \Closure
     */
    protected function getPatternHandler(array $rule)
    {
        return function ($value, $attribute) use ($rule) {
            $validator = new Regex([
                'pattern' => $rule['pattern']
            ]);
            if (!$validator->isValid($value)) {
                throw new InvalidArgumentException($rule['message'] ?? "{$this->config[$attribute]['label']}的值不能为空");
            }

            return true;
        };
    }

    /**
     * 获取`enum`处理规则
     * @param array $rule
     * @return \Closure
     */
    protected function getEnumHandler(array $rule)
    {
        return function ($value, $attribute) use ($rule) {
            if (!in_array($value, $rule['enum'])) {
                throw new InvalidArgumentException($rule['message'] ?? "{$this->config[$attribute]['label']}输入的值必须在" . implode(',', $rule['enum']) . '之中');
            }

            return true;
        };
    }

}