<?php

namespace app\common\arw\adjfut\src;

use app\common\arw\adjfut\src\Exception\ErrorMsg;
use think\facade\Request;
use think\helper\Arr;
use think\Validate as ThinkValidate;

class Validate
{
    private $data = [];

    /**
     * 设置参数s
     *
     * @param array $data
     * @return self
     */
    public function setData(array $data): self
    {
        $this->data = $data;
        return $this;
    }

    /**
     * 当条件满足时 验证
     *
     * @param array $when
     * @param array $validate
     * @param array $message
     * @param bool $batch
     * @return void
     */
    public function when(array $when, array $validate, array $message = [], bool $batch = true): void
    {
        $data = $this->data;
        $whenCount = 0;
        foreach ($when as $field => $value) {
            if (!isset($data[$field])) {
                continue;
            }
            if ($data[$field] == $value) {
                $whenCount++;
            }
        }
        $_validate = $whenCount == count($when);
        if ($_validate) {
            self::check($data, $validate, $message, $batch);
        }
    }

    /**
     * 验证是否唯一
     *
     * @param string $model 模型类
     * @param string|int $id 排除主键id
     * @param array $rules[field] => name,validateField,pk|其他规则
     * @param array $message 提示信息
     * @param bool $batch 是否批量验证
     * @return void
     * @throws ValidateException
     */
    public static function unique(
        string $model,
        $id,
        array $data,
        array $rules = [],
        array $message = [],
        bool $batch = true
    ): void {
        $_rules = [];
        foreach ($rules as $field => $validate) {
            $validates = explode('|', $validate);
            $_rule = explode(',', $validates[0]);
            $name = Arr::get($_rule, 0);
            $validateField = Arr::get($_rule, 1);
            $pk = Arr::get($_rule, 2);

            $validates[0] = self::createUniqueRule($model, [
                'field' => $validateField ?: $field,
                'id' => $id,
                'pk' => $pk,
            ]);

            $_rules[$field . ($name ? "|$name" : '')] = $validates;
        }
        self::check($data, $_rules, $message, $batch);
    }

    /**
     * 创建数据表唯一验证
     * 
     * @param string $class 模型类
     * @param array $options 配置项
     * @param string $options[field] 字段名
     * @param string $options[id] 排除ID
     * @param string $options[pk] 主键名
     * @return string
     * @date 2022-04-16
     * @example
     * @author arw
     * @since 1.0.0
     */
    public static function createUniqueRule(string $class, array $options = []): string
    {
        $field = Arr::get($options, 'field');
        $id = Arr::get($options, 'id');
        $pk = Arr::get($options, 'pk');
        if (!$field) {
            throw new ErrorMsg("字段名不能为空", 1);
        }
        return 'unique:' . join(',', [
            $class,
            $field,
            $id,
            $pk
        ]);
    }

    /**
     * 类场景验证
     *
     * @param string $validate
     * @param string $scene
     * @param boolean $batch
     * @return void
     * @throws ValidateException
     */
    public static function classScene(array $validate, array $data, bool $batch = true): void
    {
        list($class, $scene) = $validate;
        /**
         * @var ThinkValidate
         */
        $validate = new $class;
        $validate->scene($scene)->batch($batch);
        $validate->failException(true)->check($data);
    }

    /**
     * 类场景验证 param参数
     *
     * @param array $validate
     * @param boolean $batch
     * @return array
     * @throws ValidateException
     */
    public static function classSceneParam(array $validate, bool $batch = true): array
    {
        $data = Request::param();
        self::classScene($validate, $data, $batch);
        return $data;
    }


    /**
     * 类场景验证 get参数
     *
     * @param array $validate
     * @param boolean $batch
     * @return array
     * @throws ValidateException
     */
    public static function classSceneGet(array $validate, bool $batch = true): array
    {
        $data = Request::get();
        self::classScene($validate, $data, $batch);
        return $data;
    }

    /**
     * 类场景验证 post参数
     *
     * @param array $validate
     * @param boolean $batch
     * @return array
     * @throws ValidateException
     */
    public static function classScenePost(array $validate, bool $batch = true): array
    {
        $data = Request::post();
        self::classScene($validate, $data, $batch);
        return $data;
    }

    /**
     * param参数验证
     *
     * @param  array $validate 验证规则数组
     * @param  array $message  提示信息
     * @param  bool $batch    是否批量验证
     * @return array
     * @throws ValidateException
     */
    public static function param(array $validate, array $message = [], bool $batch = true): array
    {
        $data = Request::param();
        self::check($data, $validate, $message, $batch);
        return $data;
    }

    /**
     * get参数验证
     *
     * @param  array $validate 验证规则数组
     * @param  array $message  提示信息
     * @param  bool $batch    是否批量验证
     * @return array
     * @throws ValidateException
     */
    public static function get(array $validate, array $message = [], bool $batch = true): array
    {
        $data = Request::get();
        self::check($data, $validate, $message, $batch);
        return $data;
    }


    /**
     * post参数验证
     *
     * @param  array $validate 验证规则数组
     * @param  array $message  提示信息
     * @param  bool $batch    是否批量验证
     * @return array
     * @throws ValidateException
     */
    public static function post(array $validate, array $message = [], bool $batch = true): array
    {
        $data = Request::post();
        self::check($data, $validate, $message, $batch);
        return $data;
    }

    /**
     * 验证数据
     * 
     * @param  array $data     数据
     * @param  array $validate 验证规则数组
     * @param  array $message  提示信息
     * @param  bool $batch    是否批量验证
     * @return void
     * @throws ValidateException
     */
    public static function check(array $data, array $validate, array $message = [], bool $batch = true): void
    {
        $v = new ThinkValidate();
        $v->rule($validate);
        $v->message($message);
        $v->batch($batch);
        $v->failException(true)->check($data);
    }
}
