using System.Security.Cryptography;

namespace MiGu.Server.Auth;

/// <summary>
/// MiGu.Server ↔ SimpleLite 8222 之间的 **内部共享 token**。
///
/// 设计动机：SimpleLite 8222 的 EmbedIO WebApi（ReflectionApi / PersistenceApi / MapEditApi）
/// 历史上完全无鉴权，远程访问 = 接管调度内核。为不在 SimpleLite 侧实现完整 JWT 验签
/// （减少 SimpleLite 复杂度），采用一个轻量约定：
///
/// - <b>本机回环</b>（127.0.0.1 / ::1）SimpleLite 直接放行（开发机直连不受影响）；
/// - <b>其它来源</b>必须携带 <c>X-Platform-Internal-Token</c> header；
/// - MiGu.Server YARP 反代 <c>/api/sl/*</c> 到 SimpleLite 8222 时，YARP transform
///   会自动追加该 header；
/// - SimpleLite 端通过 <c>simple.json:platform.internalToken</c> 或环境变量
///   <c>SIMPLELITE__PLATFORM__INTERNALTOKEN</c> 配置同一个 token；两端不一致即拒绝。
///
/// Token 来源优先级：
///   1) appsettings.json:Internal:Token 显式配置（生产推荐：strong, length ≥ 32）
///   2) 环境变量 PLATFORM__INTERNAL__TOKEN
///   3) 兜底：进程随机 64 字节 base64，并在日志告警 + 写入 <c>data/.internal-token</c>
///      文件供本机 SimpleLite 读取（同机部署常见场景）
/// </summary>
public sealed class InternalTokenStore
{
    public string Token { get; }
    public bool IsEphemeral { get; }
    public string? PersistedFilePath { get; }

    public InternalTokenStore(IConfiguration config, IWebHostEnvironment env, ILogger<InternalTokenStore> logger)
    {
        var configured = config["Internal:Token"];
        if (!string.IsNullOrWhiteSpace(configured) && configured != "REPLACE_ME")
        {
            Token = configured;
            IsEphemeral = false;
            logger.LogInformation("Internal token 从配置读取（长度 {Len}）。", Token.Length);
            return;
        }

        // 兜底：进程随机 + 落地到 data/.internal-token 便于同机 SimpleLite 读取
        var dataDir = Path.Combine(env.ContentRootPath, "data");
        Directory.CreateDirectory(dataDir);
        var file = Path.Combine(dataDir, ".internal-token");
        if (File.Exists(file))
        {
            try
            {
                var existing = File.ReadAllText(file).Trim();
                if (existing.Length >= 32)
                {
                    Token = existing;
                    IsEphemeral = false;
                    PersistedFilePath = file;
                    logger.LogInformation("Internal token 复用 {File}（长度 {Len}）。", file, Token.Length);
                    return;
                }
            }
            catch (Exception ex)
            {
                logger.LogWarning(ex, "读取 {File} 失败，将重新生成 internal token。", file);
            }
        }

        Token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(48));
        IsEphemeral = true;
        try
        {
            File.WriteAllText(file, Token);
            PersistedFilePath = file;
            logger.LogWarning(
                "Internal token 未配置 —— 已生成进程随机值并写入 {File}（重启后保留）。" +
                "若 MiGu.Server 与 SimpleLite 不在同一台机器，请把同一个值写入 SimpleLite 端 simple.json:platform.internalToken。",
                file);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "internal token 落盘失败 —— 远程 SimpleLite 调用将无法通过鉴权（每次重启 token 都不同）。");
        }
    }
}
