<?php
declare(strict_types=1);

/**
 * 权限模型，对应 sys_permission 表
 * 编码规则：5位，仅大写字母与数字；第3/4/5位（0-indexed下标2/3/4）从左到右第一个非0的位置决定层级：
 * 三位都是0 -> 1级（顶级）；第3位非0、第4/5位是0 -> 2级；第4位非0、第5位是0 -> 3级；第5位非0 -> 4级
 * 父级编码 = 把当前层级那一位往后全部置0
 */
class Permission extends Model
{
    protected string $table = 'sys_permission';
    protected string $key = 'sys_permission_code';

    public static function isValidCode(string $code): bool
    {
        return (bool) preg_match('/^[A-Z0-9]{5}$/', $code);
    }

    /**
     * @return array{0:int,1:?string} [层级, 父级编码（顶级为 null）]
     */
    public static function deriveLevelAndParent(string $code): array
    {
        [$p2, $p3, $p4] = [$code[2], $code[3], $code[4]];

        if ($p2 === '0' && $p3 === '0' && $p4 === '0') {
            return [1, null];
        }
        if ($p3 === '0' && $p4 === '0') {
            return [2, substr($code, 0, 2) . '000'];
        }
        if ($p4 === '0') {
            return [3, substr($code, 0, 3) . '00'];
        }

        return [4, substr($code, 0, 4) . '0'];
    }

    /**
     * 整棵权限树，按编码排序，供前端 dxTreeList（keyExpr=code, parentIdExpr=parentCode）直接用
     */
    public function tree(): array
    {
        $rows = $this->db->select($this->table, [
            'sys_permission_code',
            'sys_permission_name',
            'sys_permission_level',
            'sys_permission_parent_code',
            'sys_permission_types',
            'sys_permission_extra_schema',
            'sys_permission_enabled',
        ], ['ORDER' => ['sys_permission_code' => 'ASC']]);

        foreach ($rows as &$row) {
            $row['sys_permission_types'] = $row['sys_permission_types']
                ? (json_decode($row['sys_permission_types'], true) ?: [])
                : [];
            $row['sys_permission_extra_schema'] = $row['sys_permission_extra_schema']
                ? (json_decode($row['sys_permission_extra_schema'], true) ?: [])
                : null;
        }

        return $rows;
    }

    public function gridInsert(array $values): mixed
    {
        $code = (string) ($values['sys_permission_code'] ?? '');
        if (!self::isValidCode($code)) {
            throw new MvcException('权限码必须是5位大写字母与数字');
        }

        [$level, $parentCode] = self::deriveLevelAndParent($code);
        if ($parentCode !== null && !$this->db->get($this->table, [$this->key], [$this->key => $parentCode])) {
            throw new MvcException("父级权限码 {$parentCode} 不存在，请先创建上一级");
        }

        $values['sys_permission_level'] = $level;
        $values['sys_permission_parent_code'] = $parentCode;
        $values['sys_permission_types'] = $this->normalizeJson($values['sys_permission_types'] ?? null, ['view' => '查看']);
        $values['sys_permission_extra_schema'] = $this->normalizeJson($values['sys_permission_extra_schema'] ?? null, null);

        return parent::gridInsert($values);
    }

    public function gridUpdate(mixed $key, array $values): int
    {
        // 编码是主键，不允许改；层级/父级编码由编码派生，不允许直接改
        unset($values['sys_permission_code'], $values['sys_permission_level'], $values['sys_permission_parent_code']);

        if (array_key_exists('sys_permission_types', $values)) {
            $values['sys_permission_types'] = $this->normalizeJson($values['sys_permission_types'], ['view' => '查看']);
        }
        if (array_key_exists('sys_permission_extra_schema', $values)) {
            $values['sys_permission_extra_schema'] = $this->normalizeJson($values['sys_permission_extra_schema'], null);
        }

        return parent::gridUpdate($key, $values);
    }

    private function normalizeJson(mixed $value, mixed $default): ?string
    {
        if ($value === null || $value === '') {
            return $default === null ? null : json_encode($default, JSON_UNESCAPED_UNICODE);
        }

        return is_string($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE);
    }
}
