using Ayay.SerilogLogs;
using Microsoft.Extensions.Hosting;
using Serilog;
using SHH.CameraSdk;
using System.Diagnostics;

namespace SHH.CameraService;

/// <summary>
/// 父进程守护服务 (BackgroundService)
/// <para>核心逻辑：定期检查启动本服务的父进程是否存活，若父进程退出（如 UI 崩溃），则触发本服务自动退出，避免孤儿进程占用相机硬件资源。</para>
/// </summary>
public class ParentProcessSentinel : BackgroundService
{
    private readonly ServiceConfig _config;
    private readonly IHostApplicationLifetime _lifetime;
    private ILogger _sysLog = Log.ForContext("SourceContext", LogModules.Core);

    /// <summary>
    /// 使用统一的结构化日志记录器，SourceContext 设置为 Core 模块
    /// </summary>
    public ParentProcessSentinel(
        ServiceConfig config,
        IHostApplicationLifetime lifetime)
    {
        _config = config;
        _lifetime = lifetime;
    }

    /// <summary>
    /// 执行后台守护逻辑
    /// </summary>
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        int pid = _config.ParentPid;
        // 1. 验证 PID 合法性。如果 PID 为 0 或负数，可能是手动启动调试模式，不执行守护逻辑
        if (pid <= 0)
        {
            _sysLog.Warning("[Sentinel] 未指定有效的父进程 PID ({ParentPid})，守护模式已禁用，服务将持续运行.", pid);
            return;
        }

        _sysLog.Information("[Sentinel] 父进程守护已启动，正在监控目标 PID: {ParentPid}", pid);

        while (!stoppingToken.IsCancellationRequested)
        {
            if (!IsParentRunning(pid))
            {
                _sysLog.Warning("[Sentinel] ### ALERT ### 检测到父进程 (PID:{ParentPid}) 已退出！正在下发系统终止信号...", pid);

                // 触发程序优雅退出
                _lifetime.StopApplication();

                // 强制跳出循环
                break;
            }

            // 每 2 秒检查一次，避免 CPU 浪费
            await Task.Delay(2000, stoppingToken);
        }
    }

    /// <summary>
    /// 核心状态判定：通过 PID 获取进程快照并检查存活状态
    /// </summary>
    /// <param name="pid">父进程 ID</param>
    /// <returns>存活返回 True，已消亡返回 False</returns>
    private bool IsParentRunning(int pid)
    {
        try
        {
            // 尝试获取进程对象
            var process = Process.GetProcessById(pid);

            // 检查是否已退出
            if (process.HasExited) return false;

            return true;
        }
        catch (ArgumentException)
        {
            // GetProcessById 在找不到 PID 时会抛出 ArgumentException
            // 说明进程已经不存在了
            return false;
        }
        catch (Exception ex)
        {
            _sysLog.Debug("[Sentinel] 无法定位 PID 为 {ParentPid} 的进程，判定为已退出.", pid);
            return true; // 发生未知错误时，保守起见认为它还活着
        }
    }
}