using System.Reflection;
using ShrinkNetwork;
using ShrinkNetwork.ServerHost;
using ShrinkNetwork.ServerHost.Framework;

ShrinkNetworkLogger.InfoHandler = msg => Console.WriteLine(msg);
ShrinkNetworkLogger.WarningHandler = msg => Console.WriteLine("[Warn] " + msg);
ShrinkNetworkLogger.ErrorHandler = msg => Console.Error.WriteLine(msg);
ShrinkNetworkLogger.ExceptionHandler = ex => Console.Error.WriteLine(ex);

var config = ServerHostProperties.LoadOrCreate();
var options = config.Options;
var modules = DiscoverModules();
var app = new ShrinkDedicatedServerApp(options, modules);

await app.StartAsync();

Console.WriteLine("ShrinkNetwork 独立服务器模板已启动。");
Console.WriteLine($"配置文件：{config.FilePath}");
Console.WriteLine($"首次生成默认配置：{config.CreatedDefaultFile}");
foreach (var warning in config.Warnings)
    Console.WriteLine($"[Warn] 配置文件：{warning}");
Console.WriteLine($"TCP: 0.0.0.0:{options.Port}");
Console.WriteLine($"KCP: 0.0.0.0:{options.Port}");
Console.WriteLine($"Unity 扫描输出目录：{options.ScanOutputDirectory}");
Console.WriteLine($"Unity 资产扫描目录：{options.UnityAssetsPath}");
Console.WriteLine($"共享口令鉴权已启用：{!string.IsNullOrWhiteSpace(options.SharedAuthToken)}");
Console.WriteLine($"缺少口令时允许匿名登录：{options.AllowAnonymousWhenAuthTokenMissing}");
Console.WriteLine($"会话令牌已启用：{options.EnableSessionTokens}");
Console.WriteLine($"会话令牌 TTL(秒)：{options.SessionTokenTtlSeconds}");
Console.WriteLine($"会话令牌续期窗口(秒)：{options.SessionTokenRefreshWindowSeconds}");
Console.WriteLine($"会话令牌校验失败时断开会话：{options.DisconnectOnInvalidSessionToken}");
Console.WriteLine($"协议版本范围：{options.MinProtocolVersion}-{options.MaxProtocolVersion}");
Console.WriteLine($"Schema 版本范围：{options.MinSchemaVersion}-{options.MaxSchemaVersion}");
Console.WriteLine($"TCP TLS 已启用：{options.EnableTcpTls}");
if (options.EnableTcpTls)
{
    Console.WriteLine($"TCP TLS 证书路径：{options.TcpTlsCertificatePath}");
    Console.WriteLine($"TCP TLS SNI/目标主机：{options.TcpTlsTargetHost}");
}
if (string.IsNullOrWhiteSpace(options.SharedAuthToken) && !options.AllowAnonymousWhenAuthTokenMissing)
{
    Console.WriteLine("[Warn] 当前未配置 SHRINK_SERVER_AUTH_TOKEN，登录请求默认会被拒绝。");
}
Console.WriteLine("[Info] 配置优先级：代码默认值 < server.properties < 环境变量");
Console.WriteLine("已加载模块：");
foreach (var module in modules)
    Console.WriteLine($"- {module.Name}");
Console.WriteLine("按 Ctrl+C 退出。");

using var metricsCts = new CancellationTokenSource();
if (options.DiagnosticsLogIntervalSeconds > 0)
    _ = RunDiagnosticsLoopAsync(app, options.DiagnosticsLogIntervalSeconds, metricsCts.Token);

Console.CancelKeyPress += (_, args) =>
{
    args.Cancel = true;
    metricsCts.Cancel();
    DumpDiagnostics(app);
    Environment.Exit(0);
};

try
{
    await Task.Delay(Timeout.Infinite, metricsCts.Token);
}
catch (OperationCanceledException)
{
}

static IShrinkServerModule[] DiscoverModules()
{
    return Assembly.GetExecutingAssembly()
        .GetTypes()
        .Where(type => typeof(IShrinkServerModule).IsAssignableFrom(type))
        .Where(type => !type.IsAbstract && !type.IsInterface)
        .Where(type => type.GetConstructor(Type.EmptyTypes) != null)
        .Select(type => (IShrinkServerModule)Activator.CreateInstance(type)!)
        .OrderBy(module => module.Name, StringComparer.Ordinal)
        .ToArray();
}

static async Task RunDiagnosticsLoopAsync(ShrinkDedicatedServerApp app, int intervalSeconds, CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
        try
        {
            await Task.Delay(TimeSpan.FromSeconds(intervalSeconds), cancellationToken);
        }
        catch (OperationCanceledException)
        {
            break;
        }

        DumpDiagnostics(app);
    }
}

static void DumpDiagnostics(ShrinkDedicatedServerApp app)
{
    Console.WriteLine("[Metrics] ShrinkNetwork service snapshots:");
    foreach (var pair in app.Context.Services.OrderBy(item => item.Key, StringComparer.OrdinalIgnoreCase))
    {
        var metrics = pair.Value.GetDiagnosticsSnapshot();
        Console.WriteLine(
            $"[Metrics][{pair.Key}] sessions={metrics.CurrentSessions} connected={metrics.SessionsConnected} disconnected={metrics.SessionsDisconnected} sent={metrics.PacketsSent}/{metrics.BytesSent}B recv={metrics.PacketsReceived}/{metrics.BytesReceived}B rpc={metrics.RpcStarted}/{metrics.RpcCompleted} timeout={metrics.RpcTimedOut} canceled={metrics.RpcCanceled} failed={metrics.RpcFailed} proto={metrics.ProtocolViolations} authRejected={metrics.AuthRejectedCount} denied={metrics.PermissionDeniedCount} handlerEx={metrics.HandlerExceptionCount} unknownOpcode={metrics.UnknownOpcodeCount} dispatchMiss={metrics.DispatchMissCount} serialization={metrics.SerializationErrorCount} queueReject={metrics.DispatchQueueRejectedCount}");
    }
}
