<?php

declare(strict_types=1);

namespace app\common\middleware;

use Webman\MiddlewareInterface;
use Webman\Http\Request;
use Webman\Http\Response;

/**
 * 加载控制器语言包中间件（Webman 迁移版，等价 ThinkPHP LoadLangPack）
 * 根据当前路由加载对应控制器的语言包到 Translator
 */
class LoadLangPack implements MiddlewareInterface
{
    public function process(Request $request, callable $handler): Response
    {
        $path = trim($request->path(), '/');
        if (str_starts_with($path, 'api/') || str_starts_with($path, 'admin/')) {
            $this->loadLang($request);
        }
        return $handler($request);
    }

    /**
     * 解析当前请求语言。
     * - 后台 admin：优先请求头 think-lang（zh-cn / en），其次 lang 头，再次查询/表单参数 lang（支持 zh→zh-cn）。
     * - 对外 api：优先查询/表单参数 lang（zh / zh-cn / en），其次 lang 头，再次 think-lang；仅当解析结果为允许列表中的 zh-cn 或 en 时生效，否则固定 zh-cn（不使用 Accept-Language）。仅 lang=en（规范化后）返回英文文案。
     */
    protected function resolveLangSet(Request $request): string
    {
        $path = trim($request->path(), '/');
        $parts = explode('/', $path);
        $app = $parts[0] ?? 'api';

        $queryRaw = $request->get('lang');
        if ($queryRaw === null || $queryRaw === '') {
            $queryRaw = $request->post('lang');
        }
        $queryLang = '';
        if (is_string($queryRaw)) {
            $queryLang = $queryRaw;
        } elseif (is_scalar($queryRaw)) {
            $queryLang = trim('' . $queryRaw);
        }

        $thinkRaw = $request->header('think-lang', '');
        $thinkLang = '';
        if (is_string($thinkRaw)) {
            $thinkLang = $thinkRaw;
        } elseif (is_array($thinkRaw) && isset($thinkRaw[0]) && is_string($thinkRaw[0])) {
            $thinkLang = $thinkRaw[0];
        }

        $headerLangRaw = $request->header('lang', '');
        $headerLang = '';
        if (is_string($headerLangRaw)) {
            $headerLang = $headerLangRaw;
        } elseif (is_array($headerLangRaw) && isset($headerLangRaw[0]) && is_string($headerLangRaw[0])) {
            $headerLang = $headerLangRaw[0];
        }

        $normalize = static function (string $raw): string {
            $s = str_replace('_', '-', strtolower(trim($raw)));
            if ($s === 'zh') {
                return 'zh-cn';
            }

            return $s;
        };

        $allowLangList = config('lang.allow_lang_list', ['zh-cn', 'en']);

        $candidates = [];
        if ($app === 'admin') {
            if ($thinkLang !== '') {
                $candidates[] = $normalize($thinkLang);
            }
            if ($headerLang !== '') {
                $candidates[] = $normalize($headerLang);
            }
            if ($queryLang !== '') {
                $candidates[] = $normalize($queryLang);
            }
        } else {
            if ($queryLang !== '') {
                $candidates[] = $normalize($queryLang);
            }
            if ($headerLang !== '') {
                $candidates[] = $normalize($headerLang);
            }
            if ($thinkLang !== '') {
                $candidates[] = $normalize($thinkLang);
            }
        }

        foreach ($candidates as $code) {
            if ($code !== '' && in_array($code, $allowLangList, true)) {
                return $code;
            }
        }

        // 对外 api：无显式 lang / think-lang 时默认中文，避免浏览器 Accept-Language: en 覆盖产品默认
        if ($app === 'api') {
            return 'zh-cn';
        }

        $acceptRaw = $request->header('accept-language');
        $acceptLang = is_string($acceptRaw) ? $acceptRaw : '';
        if (preg_match('/^zh[-_]?cn|^zh/i', $acceptLang)) {
            return 'zh-cn';
        }
        if (preg_match('/^en/i', $acceptLang)) {
            return 'en';
        }

        $defaultRaw = config('lang.default_lang', config('translation.locale', 'zh-cn'));
        $default = is_string($defaultRaw) ? $defaultRaw : 'zh-cn';

        return str_replace('_', '-', strtolower($default));
    }

    protected function loadLang(Request $request): void
    {
        $langSet = $this->resolveLangSet($request);

        // 设置当前请求的翻译语言，使 __() 和 trans() 使用正确的语言
        if (function_exists('locale')) {
            locale($langSet);
        }

        $path = trim($request->path(), '/');
        $parts = explode('/', $path);
        $app = $parts[0] ?? 'api';

        $appLangDir = base_path() . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . $app . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR;

        if (!class_exists(\support\Translation::class)) {
            return;
        }

        $translator = \support\Translation::instance();

        // 1. 加载根级语言包（zh-cn.php / en.php），供 common 翻译使用
        $rootLangFile = $appLangDir . $langSet . '.php';
        if (is_file($rootLangFile)) {
            $translator->addResource('phpfile', $rootLangFile, $langSet, 'messages');
        }

        // 1.5 公共语言包（app/common/lang/{locale}/*.php），供 common 服务层与多应用共用
        $commonLangPattern = base_path() . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'common' . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $langSet . DIRECTORY_SEPARATOR . '*.php';
        foreach (glob($commonLangPattern) ?: [] as $commonLangFile) {
            $translator->addResource('phpfile', $commonLangFile, $langSet, 'messages');
        }

        // 2. 加载控制器专用语言包（如 zh-cn/auth/group.php），供 get_route_remark 等使用
        //    同时加载到 messages 域，使 __() 能正确翻译控制器内的文案（如安装页错误提示）
        $controllerPath = get_controller_path($request);
        if ($controllerPath) {
            $controllerPathForFile = str_replace('.', '/', $controllerPath);
            $controllerPathForFile = implode('/', array_map(function ($p) {
                return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $p));
            }, explode('/', $controllerPathForFile)));
            $controllerLangFile = $appLangDir . $langSet . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $controllerPathForFile) . '.php';
            if (is_file($controllerLangFile)) {
                $translator->addResource('phpfile', $controllerLangFile, $langSet, $controllerPath);
                $translator->addResource('phpfile', $controllerLangFile, $langSet, 'messages');
            }
        }
    }
}
