using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

namespace SHH.ProcessLaunchers
{
    /// <summary>
    /// 进程管理器核心接口
    /// </summary>
    public interface IProcessManager
    {
        /// <summary>
        /// 注册一个要管理的进程配置
        /// </summary>
        /// <param name="config">进程配置对象</param>
        void Register(ProcessConfig config);

        /// <summary>
        /// 启动指定名称的进程
        /// </summary>
        /// <param name="name">配置中定义的 Name</param>
        void Start(string name);

        /// <summary>
        /// 启动所有已注册的进程
        /// </summary>
        Task StartAllAsync();

        /// <summary>
        /// 停止指定进程 (优雅或强制)
        /// </summary>
        /// <param name="name">进程名称</param>
        void Stop(string name);

        /// <summary>
        /// 停止所有进程
        /// </summary>
        void StopAll();

        /// <summary>
        /// 获取指定进程的资源监控复位接口
        /// </summary>
        /// <param name="processName">进程名称</param>
        void ResetGuard(string processName);

        /// <summary>
        /// 获取所有进程的实时状态快照
        /// </summary>
        List<ProcessInfoSnapshot> GetSnapshot();

        // --- 事件定义 ---

        /// <summary>
        /// 当接收到子进程的标准输出或错误流时触发
        /// </summary>
        event EventHandler<ProcessOutputEventArgs> OnOutputReceived;

        /// <summary>
        /// 当进程生命周期状态发生变化时触发
        /// </summary>
        event EventHandler<ProcessStateEventArgs> OnStateChanged;
    }

    public class MemoryGuard : IResourceGuard
    {
        public string Name => "MemoryGuard";

        private readonly long _warningBytes;
        private readonly long _criticalBytes;
        private readonly TimeSpan _alertDuration; // 持续时间阈值 (如 3分钟)

        // --- 内部状态 ---
        private DateTime? _firstOverLimitTime; // 第一次检测到超限的时间
        private bool _isAlertLatched = false;  // 是否已经报过警 (自锁)

        /// <summary>
        /// 智能内存哨兵
        /// </summary>
        /// <param name="warningMb">警告阈值</param>
        /// <param name="criticalMb">熔断阈值</param>
        /// <param name="durationMinutes">必须持续超限多少分钟才报警</param>
        public MemoryGuard(int warningMb, int criticalMb, int durationMinutes = 3)
        {
            _warningBytes = (long)warningMb * 1024 * 1024;
            _criticalBytes = (long)criticalMb * 1024 * 1024;
            _alertDuration = TimeSpan.FromMinutes(durationMinutes);
        }

        public GuardResult Check(Process process, out string reason)
        {
            reason = null;
            try
            {
                process.Refresh();
                long currentUsage = process.WorkingSet64;

                // 1. 优先检查 Critical (熔断线)
                // 逻辑：熔断涉及生死，不需要防抖，也不受“已报警”锁定的限制。
                // 哪怕用户标记了已处置，只要内存爆了，必须重启。
                if (currentUsage > _criticalBytes)
                {
                    reason = $"[严重] 内存 {FormatSize(currentUsage)} > 熔断线 {FormatSize(_criticalBytes)} (立即执行管控)";
                    // 重启后，物理进程会变，下一次 Check 会是新进程，状态建议在重启时由外部重置，
                    // 或者这里不重置，依靠 ProcessManager 重启后重新创建 Guard 实例。
                    return GuardResult.Critical;
                }

                // 2. 检查 Warning (警告线) - 包含防抖和自锁逻辑
                if (currentUsage > _warningBytes)
                {
                    // A. 如果已经报过警 (已锁定)，则不再报，保持沉默
                    if (_isAlertLatched)
                    {
                        return GuardResult.Normal;
                    }

                    // B. 如果是刚发现超限，记录时间
                    if (_firstOverLimitTime == null)
                    {
                        _firstOverLimitTime = DateTime.Now;
                        // 这里可以选做：记录一条 Info 日志，告诉用户"正在观察中"
                        // reason = $"内存超限 {FormatSize(currentUsage)}，开始计时观察...";
                        return GuardResult.Normal; // 暂时不报 Warning
                    }

                    // C. 检查持续时间
                    var duration = DateTime.Now - _firstOverLimitTime.Value;
                    if (duration >= _alertDuration)
                    {
                        // 满足持续时间 -> 触发报警并锁定
                        _isAlertLatched = true;
                        _firstOverLimitTime = null; // 计时归零

                        reason = $"[报警] 内存 {FormatSize(currentUsage)} > 阈值 {FormatSize(_warningBytes)} 且持续超过 {_alertDuration.TotalMinutes}分钟";
                        return GuardResult.Warning; // 抛出信号，发邮件！
                    }
                    else
                    {
                        // 还没到时间
                        return GuardResult.Normal;
                    }
                }
                else
                {
                    // 3. 内存正常
                    // 逻辑：如果之前在计时（比如超了1分钟），现在降下来了，则计时器清零。
                    // 但如果已经报过警 (_isAlertLatched=true)，则保持锁定，不自动复位。
                    // 除非用户手动点 Reset。

                    if (_firstOverLimitTime != null)
                    {
                        _firstOverLimitTime = null; // 波动防抖：由于降下来了，重置观察计时
                    }

                    return GuardResult.Normal;
                }
            }
            catch
            {
                return GuardResult.Normal;
            }
        }

        /// <summary>
        /// 用户点击“已处置”时调用
        /// </summary>
        public void Reset()
        {
            _isAlertLatched = false;
            _firstOverLimitTime = null;
        }

        private string FormatSize(long bytes) => $"{bytes / 1024 / 1024}MB";
    }
}