using Ayay.SerilogLogs;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using SHH.CameraSdk;

namespace SHH.CameraService;

public class Program
{
    private static bool _isExiting = false;

    /// <summary>
    /// 主程序
    /// </summary>
    /// <param name="args"></param>
    /// <returns></returns>
    public static async Task Main(string[] args)
    {
        // 1. [核心环境] 必须在所有网络操作前开启
        AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

        // 2. 解析配置与初始化日志
        var (config, opts, isDebugArgs) = Bootstrapper.ParseConfigAndInitLogger(args);
        var sysLog = Log.ForContext("SourceContext", LogModules.Core);

        // =============================================================
        // 1. 启动日志
        // =============================================================
        sysLog.Warning($"[Core] 🚀 视频取流进程启动, 日志组件初始化完毕 => 进程: {opts.AppId}");

        string argString = string.Join(" ", args);
        sysLog.Debug($"[Core] 🚀 启动参数（{(isDebugArgs ? "调试环境" : "生产环境")}）: {argString}");

        AppDomain.CurrentDomain.ProcessExit += (s, e) => HandleExit("ProcessExit");
        Console.CancelKeyPress += (s, e) => {
            e.Cancel = true; // 阻止立即强制杀死进程
            HandleExit("CancelKeyPress");
        };

        // =============================================================
        // 2. 硬件预热、端口扫描、gRpc链接
        // =============================================================
        Bootstrapper.WarmUpHardware(sysLog);

        // 端口自动扫描 (必须做，否则端口冲突)
        int activePort = Bootstrapper.ScanForAvailablePort(config, sysLog);
        if (activePort == -1)
        {
            sysLog.Fatal("[Core] 💀 无法启动：配置范围内无可用端口");
            Bootstrapper.Shutdown("无法启动：配置范围内无可用端口", exitCode: 1);
            return;
        }
        config.UpdateActualPort(activePort); // 回填端口

        // 具体的 gRpc 链接逻辑封装在 Bootstrapper 中，保持 Main 清爽但逻辑可见
        await Bootstrapper.RegisterToGatewayAsync(config);

        // =============================================================
        // 3. 构建 Web 主机环境
        // =============================================================
        var builder = WebApplication.CreateBuilder(args);

        // 👇👇👇 核心修复开始 👇👇👇

        // ★ 1. 接管日志系统：告诉 Host 使用我们刚才配置好的 Serilog
        // dispose: true 表示程序结束时自动刷新日志
        builder.Host.UseSerilog(dispose: true);

        // ★ 2. 斩草除根：清除 .NET 默认注入的 Console/Debug 日志提供程序
        // 这一步是解决 "info: Microsoft.Hosting.Lifetime..." 重复输出的关键
        builder.Logging.ClearProviders();

        // ★ 3. (可选) 彻底静音：禁止 Kestrel 打印 "Now listening on..." 这种启动横幅
        // 如果你只想看你自己的 "[WebApi] 🚀 服务启动..."，就把这行加上
        builder.WebHost.SuppressStatusMessages(true);

        // ★ 核心改动：一行代码注册所有业务 (SDK, Workers, gRpc, 视频流)
        builder.Services.AddCameraBusinessServices(config, sysLog);

        // ★ 核心改动：注册 Web 基础 (Controller, Swagger, Cors)
        builder.Services.AddWebSupport(config);

        // =============================================================
        // 6. 启动服务
        // =============================================================
        var app = builder.Build();

        // 激活 SDK 管理器并启动业务点火
        await StartBusinessLogic(app, sysLog);

        // ★ 核心改动：配置 HTTP 管道 (Swagger, MapControllers 等)
        app.ConfigurePipeline(config);

        // 启动监听
        string url = $"http://0.0.0.0:{config.BasePort}";
        sysLog.Information($"[WebApi] 🚀 服务启动，监听: {url}");

        await app.RunAsync(url);
    }

    /// <summary>
    /// 激活单例并启动相机管理器
    /// </summary>
    /// <param name="app"></param>
    /// <param name="logger"></param>
    static async Task StartBusinessLogic(WebApplication app, Serilog.ILogger logger)
    {
        var manager = app.Services.GetRequiredService<CameraManager>();

        // 激活哨兵
        _ = app.Services.GetRequiredService<ConnectivitySentinel>();
        
        await manager.StartAsync();

        // 2. Optimized: 主动拉起所有已加载设备的物理连接
        // 理由：当本地配置了 video 推送目标时，不再等待远端 command 下发启动指令
        var allDevices = manager.GetAllDevices();
        foreach (var device in allDevices)
        {
            if (device.IsRunning && !device.IsActived)
            {
                logger.Information($"[Core] 🚀 自动激活设备流: ID:{device.Id} IP:{device.Config.IpAddress}");
                // 使用 Fire-and-forget 启动，避免阻塞主线程
                _ = device.StartAsync();
            }
        }

        var sysLog = Log.ForContext("SourceContext", LogModules.Core);
        sysLog.Information($"[Core] 🚀 核心业务逻辑已激活, 设备管理器已就绪.");
    }

    /// <summary>
    /// 退出, 刷新日志
    /// </summary>
    /// <param name="source"></param>
    private static void HandleExit(string source)
    {
        if (_isExiting) return;
        _isExiting = true;

        Log.ForContext("SourceContext", LogModules.Core)
            .Warning("// Modified: 处理手动关闭请求。来源: {Source}", source);

        // TODO: 执行 SHH.CameraService 的清理逻辑 (释放海康/大华 SDK 句柄)
        Log.ForContext("SourceContext", LogModules.Core)
            .Warning("SHH.CameraService 已安全关闭，日志已刷新。");

        // 必须显式调用，否则在 ProcessExit 触发时异步日志可能丢失
        Log.CloseAndFlush();

        Environment.Exit(0);
    }
}

/*
🚀	启动/发布	程序启动、服务预热、开始监听
🏁	结束/终点	批量任务全部完成、程序正常退出
🔄	重试/循环	正在重试连接、定时任务触发、同步数据中
⏳	等待/耗时	长耗时操作开始、排队中
💤	休眠/闲置	线程挂起、服务进入待机模式
🌐	网络/HTTP	HTTP 请求、API 调用、Web 服务
🔌	连接	数据库连接建立、Socket 连接
📡	信号/广播	发送 MQ 消息、广播通知、取流
💾	存储/磁盘	写入文件、数据库落盘、缓存读写
🔒	安全/锁	加密、解密、登录成功、获取分布式锁
⚙️	配置/系统	加载配置、系统底层操作
🐞	Bug/调试	捕捉到的异常、临时调试信息
🧪	测试/实验	单元测试环境、灰度测试代码
🔍	搜索/检查	查询数据库、检查文件是否存在
💡	提示/发现	逻辑分支提示、参数值打印
🔴 红：致命/严重 (Fatal/Error)
🟡 黄：警告 (Warning)
🟢 绿：正常/成功 (Info/Success)
🔵 蓝：数据/网络 (Data/Network)
⚪ 灰：细节/忽略 (Debug/Verbose)
✅	Check Mark Button	\u{2705}	&#x2705;
🆗	OK Button	\u{1F197}	&#x1F197;
🔚	END Arrow (逻辑结束)	\u{1F51A}	&#x1F51A;
💯	Hundred Points (完美结束)	\u{1F4AF}	&#x1F4AF;
🛑	Stop Sign (最强提示)	\u{1F6D1}	&#x1F6D1;
⛔	No Entry (禁止/中断)	\u{26D4}	&#x26D4;
🚫	Prohibited (非法操作终止)	\u{1F6AB}	&#x1F6AB;
⏹️	Stop Button (播放器风格)	\u{23F9}	&#x23F9;
❌	Cross Mark (任务失败结束)	\u{274C}	&#x274C;
💀	Skull (进程被 Kill)	\u{1F480}	&#x1F480;
⚰️	Coffin (彻底销毁)	\u{26B0}	&#x26B0;
👻	Ghost (变成孤儿进程)	\u{1F47B}	&#x1F47B;
 */