<?php

declare(strict_types=1);

namespace App\Support;

use App\Lottery\ErrorCode;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

/**
 * API 响应文案（zh / en / ne），供 msg 字段与 RuntimeException reason 翻译。
 */
final class ApiMessage
{
    /** @var list<string> */
    private const LOOKUP_PREFIXES = ['api.reasons.', 'api.', 'admin.', 'sso.', 'jackpot.', 'wallet.'];

    public static function locale(?Request $request = null): string
    {
        $request ??= request();

        if ($request instanceof Request && $request->attributes->has('lottery_locale')) {
            return (string) $request->attributes->get('lottery_locale');
        }

        return LotteryLocale::resolve($request instanceof Request ? $request : null);
    }

    /**
     * @param  array<string, string|int|float>  $replace
     */
    public static function get(?Request $request, string $key, array $replace = []): string
    {
        $key = trim($key);
        if ($key === '') {
            return self::translateKey($request, 'api.client_error', $replace);
        }

        if (preg_match('/\p{Han}/u', $key) === 1) {
            return $key;
        }

        $resolved = self::translateKey($request, $key, $replace);
        if ($resolved !== null) {
            return $resolved;
        }

        return $key;
    }

    /**
     * RuntimeException / 业务 reason 机器码 → 用户可见文案。
     *
     * @param  array<string, string|int|float>  $replace
     */
    public static function reason(?Request $request, string $reasonKey, array $replace = []): string
    {
        $reasonKey = trim($reasonKey);
        if ($reasonKey === '') {
            return self::translateKey($request, 'api.client_error', $replace)
                ?? trans('api.client_error', [], self::locale($request));
        }

        if (preg_match('/\p{Han}/u', $reasonKey) === 1) {
            return $reasonKey;
        }

        $resolved = self::translateKey($request, $reasonKey, $replace);
        if ($resolved !== null) {
            return $resolved;
        }

        $resolved = self::translateBusinessKey($request, $reasonKey, $replace);
        if ($resolved !== null) {
            return $resolved;
        }

        return $reasonKey;
    }

    /**
     * abort() / HttpException 的 message 转为用户可见文案。
     */
    public static function httpExceptionMessage(?Request $request, int $status, string $rawMessage): string
    {
        $trimmed = trim($rawMessage);
        if ($trimmed !== '') {
            if (preg_match('/\p{Han}/u', $trimmed) === 1) {
                return $trimmed;
            }

            if (str_starts_with($trimmed, 'admin.')) {
                return self::get($request, $trimmed);
            }

            $resolved = self::translateKey($request, $trimmed);
            if ($resolved !== null) {
                return $resolved;
            }

            $resolved = self::translateBusinessKey($request, $trimmed);
            if ($resolved !== null) {
                return $resolved;
            }

            if (str_contains($trimmed, ' ')) {
                return $trimmed;
            }

            return $trimmed;
        }

        return match ($status) {
            401 => self::get($request, 'admin.unauthenticated'),
            403 => self::get($request, 'admin.permission_denied'),
            404 => self::get($request, 'api.not_found'),
            422 => self::get($request, 'api.validation_failed'),
            429 => self::get($request, 'api.too_many_requests'),
            default => $status >= 500
                ? self::get($request, 'api.server_error')
                : self::get($request, 'api.client_error'),
        };
    }

    public static function successMessage(?Request $request = null): string
    {
        return self::get($request, 'success.ok');
    }

    /**
     * @param  array<string, string|int|float>  $replace
     */
    public static function errorResponse(
        ?Request $request,
        string $messageKey,
        int $code,
        mixed $data = null,
        int $httpStatus = 400,
        array $replace = [],
    ): JsonResponse {
        return ApiResponse::error(
            self::get($request, $messageKey, $replace),
            $code,
            $data,
            $httpStatus,
        );
    }

    public static function runtimeErrorResponse(
        ?Request $request,
        \RuntimeException $exception,
        int $code = 0,
        int $httpStatus = 409,
    ): JsonResponse {
        $reason = trim($exception->getMessage());
        $resolvedCode = $code !== 0 ? $code : ErrorCode::ClientHttpError->value;

        return ApiResponse::error(
            self::reason($request, $reason),
            $resolvedCode,
            ['reason' => $reason],
            $httpStatus,
        );
    }

    /**
     * @param  array<string, string|int|float>  $replace
     */
    private static function translateKey(?Request $request, string $key, array $replace = []): ?string
    {
        $locale = self::locale($request);
        $fallback = (string) config('lottery.locales.fallback', 'en');

        foreach ([$locale, $fallback] as $tryLocale) {
            foreach (self::candidateKeys($key) as $fullKey) {
                $msg = trans($fullKey, $replace, $tryLocale);
                if ($msg !== $fullKey && $msg !== '') {
                    return $msg;
                }
            }
        }

        return null;
    }

    /**
     * @param  array<string, string|int|float>  $replace
     */
    private static function translateBusinessKey(?Request $request, string $key, array $replace = []): ?string
    {
        $locale = self::locale($request);
        $fallback = (string) config('lottery.locales.fallback', 'en');
        $candidates = array_values(array_unique([
            $key,
            str_contains($key, '.') ? substr($key, strrpos($key, '.') + 1) : $key,
        ]));

        foreach ([$locale, $fallback] as $tryLocale) {
            foreach ($candidates as $candidate) {
                if ($candidate === '') {
                    continue;
                }
                $businessKey = 'validation.business.'.$candidate;
                $msg = trans($businessKey, $replace, $tryLocale);
                if ($msg !== $businessKey) {
                    return $msg;
                }
            }
        }

        return null;
    }

    /**
     * @return list<string>
     */
    private static function candidateKeys(string $key): array
    {
        $key = trim($key);
        if ($key === '') {
            return ['api.client_error'];
        }

        if (str_contains($key, '.')) {
            return array_values(array_unique([
                $key,
                'api.'.$key,
                'admin.'.$key,
                'sso.'.$key,
                'jackpot.'.$key,
                'wallet.'.$key,
                'api.reasons.'.$key,
            ]));
        }

        $keys = [];
        foreach (self::LOOKUP_PREFIXES as $prefix) {
            $keys[] = $prefix.$key;
        }

        return $keys;
    }
}
