<?php
declare(strict_types=1);

namespace app\api\util;

use support\Request;

/**
 * API 多语言（兼容 Webman 多语言配置）
 * 根据请求头 lang（zh=中文，en=英文）返回对应文案；
 * 无 lang 请求头时使用 config('translation.locale') 推断（zh_CN/zh→中文，en→英文）
 */
class ApiLang
{
    private const LANG_HEADER = 'lang';
    private const LANG_EN = 'en';
    private const LANG_ZH = 'zh';

    /** @var array<string, array<string, string>> lang => [ key => message ] */
    private static array $messages = [];

    /**
     * 从请求中获取语言：优先读 header lang，否则按 Webman config('translation.locale') 推断
     */
    public static function getLang(?Request $request = null): string
    {
        $request = $request ?? (function_exists('request') ? request() : null);
        if ($request !== null) {
            $lang = $request->header(self::LANG_HEADER);
            if ($lang !== null && $lang !== '') {
                $lang = strtolower(trim((string) $lang));
                if ($lang === self::LANG_EN) {
                    return self::LANG_EN;
                }
                if ($lang === self::LANG_ZH || $lang === 'chs') {
                    return self::LANG_ZH;
                }
            }
        }
        $locale = (string) (function_exists('config') ? config('translation.locale', 'zh_CN') : 'zh_CN');
        return stripos($locale, 'en') !== false ? self::LANG_EN : self::LANG_ZH;
    }

    /**
     * 翻译文案（对外接口 message）：
     * - 推荐：抛英文 key（如 USER_NOT_FOUND），根据 lang 返回对应语言
     * - 兼容：仍抛中文原文时，lang=en 按旧映射翻译，否则原样返回
     *
     * 语言文件优先从 Webman config('translation.path')/api/{lang}.php 加载
     */
    public static function translate(string $message, ?Request $request = null): string
    {
        $lang = self::getLang($request);
        $map = self::loadMessages($lang);
        if (isset($map[$message])) {
            return (string) $map[$message];
        }

        // 若传入的是中文/原文，则按固定规则生成英文 key（MSG_XXXXXXXX）再翻译
        $key = self::toMsgKey($message);
        if ($key !== null && isset($map[$key])) {
            return (string) $map[$key];
        }

        // 兼容旧版：历史代码直接抛中文 message，lang=en 时从 legacy_en.php 映射到英文
        if ($lang === self::LANG_EN) {
            $legacy = self::loadLegacyEnMessages();
            if (isset($legacy[$message])) {
                return (string) $legacy[$message];
            }
            if ($key !== null && isset($legacy[$key])) {
                return (string) $legacy[$key];
            }
        }

        return $message;
    }

    /**
     * 加载某语言的 API 文案（推荐：key=英文，value=对应语言文案）
     */
    private static function loadMessages(string $locale): array
    {
        if (isset(self::$messages[$locale])) {
            return self::$messages[$locale];
        }
        $path = null;
        if (function_exists('config')) {
            $base = rtrim((string) config('translation.path', ''), DIRECTORY_SEPARATOR);
            if ($base !== '') {
                $path = $base . DIRECTORY_SEPARATOR . 'api' . DIRECTORY_SEPARATOR . $locale . '.php';
            }
        }
        if ($path !== null && is_file($path)) {
            self::$messages[$locale] = require $path;
            return self::$messages[$locale];
        }

        // 回退到 app/api/lang/{lang}.php（同样使用英文 key）
        $fallback = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $locale . '.php';
        self::$messages[$locale] = is_file($fallback) ? (require $fallback) : [];
        return self::$messages[$locale];
    }

    /**
     * 将原文转换为英文 key（只包含英文字符/数字/下划线）：MSG_XXXXXXXX（crc32）
     * 若入参已经是英文 key，则返回 null（表示无需转换）
     */
    private static function toMsgKey(string $message): ?string
    {
        $trim = trim($message);
        if ($trim === '') {
            return null;
        }
        // 已经是英文错误码 key（只允许 A-Z/0-9/_，且至少 3 位）
        if (preg_match('/^[A-Z0-9_]{3,}$/', $trim) === 1) {
            return null;
        }
        return 'MSG_' . strtoupper(sprintf('%08X', crc32($trim)));
    }

    /**
     * 加载中文原文 => 英文 的兼容映射（仅 lang=en 使用）
     * @return array<string, string>
     */
    private static function loadLegacyEnMessages(): array
    {
        $path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . 'legacy_en.php';
        if (is_file($path)) {
            $data = require $path;
            if (is_array($data)) {
                return $data;
            }
        }
        return [];
    }

    /**
     * 带占位符的翻译，如 translateParams('当前玩家余额%s小于%s无法继续游戏', [$coin, $minCoin])
     * 先翻译再替换（en 文案使用 %s 占位）
     */
    public static function translateParams(string $message, array $params = [], ?Request $request = null): string
    {
        $translated = self::translate($message, $request);
        if ($params !== []) {
            $translated = sprintf($translated, ...$params);
        }
        return $translated;
    }
}
