<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
namespace app\validate\domain;

use Core\service\registry\MenuRegistry;


/**
 * 平台菜单领域验证器
 * @package app\validate\domain
 */
class PlatformMenuDomainValidator implements DomainValidatorInterface
{
    private MenuRegistry $menuRegistry;

    public function __construct(MenuRegistry $menuRegistry)
    {
        $this->menuRegistry = $menuRegistry;
    }

    /**
     * @inheritDoc
     */
    public function validate(array $data, string $scene = ''): array
    {
        $errors = match ($scene) {
            'save' => $this->validateSave($data),
            default => [],
        };

        return ['ok' => empty($errors), 'errors' => $errors];
    }


    /**
     * 校验保存菜单配置数据
     * @param array $data
     * @return array 错误信息数组
     */
    private function validateSave(array $data): array
    {
        $items = $data['items'] ?? [];
        if (!is_array($items)) {
            return ['items' => 'MENU_ITEMS_INVALID'];
        }

        $knownCodes = [];
        foreach ($this->menuRegistry->all() as $item) {
            $code = trim((string)($item['code'] ?? ''));
            if ($code !== '') {
                $knownCodes[$code] = true;
            }
        }

        $seenCodes = [];
        foreach ($items as $index => $item) {
            $prefix = 'items.' . $index;
            if (!is_array($item)) {
                return [$prefix => 'MENU_ITEM_INVALID'];
            }

            $code = trim((string)($item['code'] ?? ''));
            if ($code === '' || !isset($knownCodes[$code])) {
                return [$prefix . '.code' => 'MENU_CODE_INVALID'];
            }
            if (isset($seenCodes[$code])) {
                return [$prefix . '.code' => 'MENU_CODE_DUPLICATED'];
            }
            $seenCodes[$code] = true;

            $titleShort = trim((string)($item['title_short'] ?? ''));
            $titleFull = trim((string)($item['title_full'] ?? ''));
            if ($titleShort !== '' && $this->stringLength($titleShort) > 12) {
                return [$prefix . '.title_short' => 'MENU_TITLE_SHORT_TOO_LONG'];
            }
            if ($titleFull !== '' && $this->stringLength($titleFull) > 30) {
                return [$prefix . '.title_full' => 'MENU_TITLE_FULL_TOO_LONG'];
            }

            if (array_key_exists('order_no', $item)) {
                $orderNo = $item['order_no'];
                if (!is_numeric($orderNo) || (int)$orderNo < 0 || (int)$orderNo > 9999) {
                    return [$prefix . '.order_no' => 'MENU_ORDER_INVALID'];
                }
            }

            if (array_key_exists('hidden', $item) && !in_array((int)$item['hidden'], [0, 1], true)) {
                return [$prefix . '.hidden' => 'MENU_HIDDEN_INVALID'];
            }
            if (array_key_exists('status', $item) && !in_array((int)$item['status'], [0, 1], true)) {
                return [$prefix . '.status' => 'MENU_STATUS_INVALID'];
            }
        }

        return [];
    }


    /**
     * 计算字符串长度（优先使用mb_strlen）
     * @param string $value
     * @return int
     */
    private function stringLength(string $value): int
    {
        if (function_exists('mb_strlen')) {
            return mb_strlen($value);
        }

        return strlen($value);
    }
}