<?php
declare (strict_types = 1);

namespace app\admin\validate\v1;

use app\admin\model\v1\SysMenuModel;
use think\facade\Db;
use think\Validate;

class SysMenuValidate extends Validate
{
    /**
     * 定义验证规则
     * 格式：'字段名' =>  ['规则1','规则2'...]
     *
     * @var array
     */
    protected $rule = [
        'id'                                     => 'require|integer',
        'pid'                                    => 'integer|different:id|checkPidNotBeChildren',
        'title'                                  => 'require|max:64',
        'name'                                   => 'require|unique:sys_menu|max:64',
        'path'                                   => 'require|max:128',
        'icon'                                   => 'max:64',
        'redirect'                               => 'max:128',
        'component'                              => 'max:128',
        'hidden'                                 => 'in:0,1',
        'actived'                                => 'in:0,1',
        'keep_alive'                             => 'in:0,1',
        'sort'                                   => 'integer',
        'status'                                 => 'in:1,-1',
        'menu_ability_permission'                => 'array',
        'menu_ability_permission.*.ability_name' => 'max:64',
        'menu_ability_permission.*.permission'   => 'max:128',
        'menu_ability_permission.*.sort'         => 'integer',
    ];

    /**
     * 定义错误信息
     * 格式：'字段名.规则名' =>  '错误信息'
     *
     * @var array
     */
    protected $message = [
        'id.require'                                 => '菜单ID不能为空',
        'id.integer'                                 => '菜单ID必须为整数',
        'pid.integer'                                => '父级菜单ID必须为整数',
        'pid.different'                              => '父级菜单ID不能为自身',
        'pid.checkPidNotBeChildren'                  => '父级菜单不能为自身的子菜单',
        'title.require'                              => '菜单名称不能为空',
        'title.max'                                  => '菜单名称最多64个字符',
        'name.require'                               => '菜单Name不能为空',
        'name.unique'                                => '菜单Name已存在',
        'name.max'                                   => '菜单Name最多64个字符',
        'path.require'                               => '访问路径不能为空',
        'path.max'                                   => '访问路径最多128个字符',
        'icon.max'                                   => '菜单图标最多64个字符',
        'redirect.max'                               => '菜单重定向路径最多128个字符',
        'component.max'                              => '菜单组件路径最多128个字符',
        'hidden.in'                                  => '是否显示必须为0或1',
        'actived.in'                                 => '是否高亮必须为0或1',
        'keep_alive.in'                              => 'KeepAlive必须为0或1',
        'sort.integer'                               => '菜单排序必须为整数',
        'status.in'                                  => '是否启用必须为1或-1',
        'menu_ability_permission.array'              => '菜单能力权限必须为数组',
        'menu_ability_permission.*.ability_name.max' => '菜单能力权限名称最多64个字符',
        'menu_ability_permission.*.permission.max'   => '菜单能力权限标志最多128个字符',
        'menu_ability_permission.*.sort.integer'     => '菜单能力权限排序必须为整数',
    ];

    // 验证pid
    protected function checkPidNotBeChildren($value, $rule, $data = [])
    {
        if ($value == 0) {
            return true;
        }

        $children   = [];
        $table_name = (new SysMenuModel)->getTable();
        if (env('DB_VERSION', '5') == '8') {
            $children = Db::query(
                preg_replace(
                    '/\s+/u', 
                    ' ',
                    "WITH RECURSIVE menu_tree_by AS (
                        SELECT a.id, a.pid FROM $table_name a WHERE a.id = {$data['id']}
                        UNION ALL
                        SELECT k.id, k.pid FROM $table_name k INNER JOIN menu_tree_by t ON t.id = k.pid
                    )
                    SELECT id FROM menu_tree_by WHERE id <> {$data['id']};"
                )
            );
        } else {
            $children = \think\facade\Db::query("
                SELECT t2.id
                    FROM ( 
                        SELECT 
                            @r AS _id, (SELECT @r := GROUP_CONCAT(id) FROM $table_name WHERE FIND_IN_SET(pid, _id)) AS parent_id
                        FROM 
                            (SELECT @r := {$data['id']}) vars, $table_name h 
                        WHERE @r <> 0) t1 
                    JOIN $table_name t2 
                    ON FIND_IN_SET(t2.pid, t1._id)
                ORDER BY t2.id;
            ");
        }
        if (!empty($children) && in_array($data['pid'], array_column($children, 'id'))) {
            return false;
        }

        return true;
    }

    // 新增验证场景
    public function sceneCreate()
    {
        return $this->remove('id', 'require|integer')->remove('pid', 'different|checkPidNotBeChildren');
    }
}
