using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// 시스템 리소스 모니터 핸들러. "monitor" 프리픽스로 사용합니다.
/// CPU, 메모리, 디스크, 프로세스 수 등 실시간 시스템 리소스 정보를 표시합니다.
/// 예: monitor      → 전체 리소스 현황
///     monitor cpu  → CPU 관련 정보만
///     monitor mem  → 메모리 관련 정보만
///     monitor disk → 디스크 사용량
/// Enter → 결과를 클립보드에 복사.
/// </summary>
public class MonitorHandler : IActionHandler
{
    public string? Prefix => "monitor";

    public PluginMetadata Metadata => new(
        "Monitor",
        "시스템 리소스 모니터 — monitor",
        "1.0",
        "AX");

    [DllImport("kernel32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);

    [StructLayout(LayoutKind.Sequential)]
    private struct MEMORYSTATUSEX
    {
        public uint dwLength;
        public uint dwMemoryLoad;
        public ulong ullTotalPhys;
        public ulong ullAvailPhys;
        public ulong ullTotalPageFile;
        public ulong ullAvailPageFile;
        public ulong ullTotalVirtual;
        public ulong ullAvailVirtual;
        public ulong ullAvailExtendedVirtual;
    }

    public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
    {
        var q = query.Trim().ToLowerInvariant();
        var items = new List<LauncherItem>();

        var showAll = string.IsNullOrWhiteSpace(q);

        // CPU
        if (showAll || q.Contains("cpu") || q.Contains("프로세서"))
        {
            var cpuCount = Environment.ProcessorCount;
            var processes = Process.GetProcesses().Length;
            var threads = 0;
            try { threads = Process.GetProcesses().Sum(p => { try { return p.Threads.Count; } catch (Exception) { return 0; } }); }
            catch (Exception) { }

            items.Add(new LauncherItem(
                $"CPU: {cpuCount}코어  ·  프로세스 {processes}개  ·  스레드 {threads:N0}개",
                "Enter로 클립보드 복사",
                null, $"CPU: {cpuCount}코어, 프로세스 {processes}개, 스레드 {threads:N0}개",
                Symbol: Symbols.Processor));
        }

        // Memory
        if (showAll || q.Contains("mem") || q.Contains("ram") || q.Contains("메모리"))
        {
            var mem = new MEMORYSTATUSEX { dwLength = (uint)Marshal.SizeOf<MEMORYSTATUSEX>() };
            GlobalMemoryStatusEx(ref mem);
            var totalGB = mem.ullTotalPhys / (1024.0 * 1024 * 1024);
            var usedGB = (mem.ullTotalPhys - mem.ullAvailPhys) / (1024.0 * 1024 * 1024);
            var pct = mem.dwMemoryLoad;

            items.Add(new LauncherItem(
                $"메모리: {usedGB:F1}GB / {totalGB:F1}GB ({pct}% 사용)",
                $"사용 가능: {mem.ullAvailPhys / (1024.0 * 1024 * 1024):F1}GB  ·  Enter로 복사",
                null, $"메모리: {usedGB:F1}GB / {totalGB:F1}GB ({pct}% 사용)",
                Symbol: Symbols.Memory));
        }

        // Disk
        if (showAll || q.Contains("disk") || q.Contains("디스크") || q.Contains("저장"))
        {
            foreach (var drive in System.IO.DriveInfo.GetDrives())
            {
                if (!drive.IsReady || drive.DriveType != System.IO.DriveType.Fixed) continue;
                var totalGB = drive.TotalSize / (1024.0 * 1024 * 1024);
                var freeGB = drive.AvailableFreeSpace / (1024.0 * 1024 * 1024);
                var usedGB = totalGB - freeGB;
                var pct = (int)(usedGB / totalGB * 100);

                items.Add(new LauncherItem(
                    $"디스크 {drive.Name.TrimEnd('\\')}  {usedGB:F0}GB / {totalGB:F0}GB ({pct}%)",
                    $"여유: {freeGB:F1}GB  ·  {drive.DriveFormat}  ·  Enter로 복사",
                    null, $"디스크 {drive.Name}: {usedGB:F0}GB / {totalGB:F0}GB ({pct}%), 여유 {freeGB:F1}GB",
                    Symbol: Symbols.Storage));
            }
        }

        // Uptime
        if (showAll || q.Contains("uptime") || q.Contains("가동"))
        {
            var uptime = TimeSpan.FromMilliseconds(Environment.TickCount64);
            var uptimeStr = uptime.Days > 0
                ? $"{uptime.Days}일 {uptime.Hours}시간 {uptime.Minutes}분"
                : $"{uptime.Hours}시간 {uptime.Minutes}분";

            items.Add(new LauncherItem(
                $"가동 시간: {uptimeStr}",
                "마지막 재시작 이후 경과  ·  Enter로 복사",
                null, $"가동 시간: {uptimeStr}",
                Symbol: Symbols.Clock));
        }

        // Top processes by memory
        if (showAll || q.Contains("top") || q.Contains("프로세스"))
        {
            try
            {
                var topProcs = Process.GetProcesses()
                    .Where(p => { try { return p.WorkingSet64 > 0; } catch (Exception) { return false; } })
                    .OrderByDescending(p => { try { return p.WorkingSet64; } catch (Exception) { return 0L; } })
                    .Take(5)
                    .Select(p =>
                    {
                        try { return $"{p.ProcessName} ({p.WorkingSet64 / (1024 * 1024)}MB)"; }
                        catch (Exception) { return p.ProcessName; }
                    });

                items.Add(new LauncherItem(
                    "메모리 상위 프로세스",
                    string.Join(", ", topProcs),
                    null, $"메모리 상위: {string.Join(", ", topProcs)}",
                    Symbol: Symbols.Computer));
            }
            catch (Exception) { }
        }

        if (items.Count == 0)
        {
            items.Add(new LauncherItem(
                $"'{q}'에 해당하는 리소스 항목 없음",
                "cpu / mem / disk / uptime / top",
                null, null, Symbol: Symbols.Warning));
        }

        return Task.FromResult<IEnumerable<LauncherItem>>(items);
    }

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is string text && !string.IsNullOrWhiteSpace(text))
        {
            try { Application.Current?.Dispatcher.Invoke(() => Clipboard.SetText(text)); }
            catch (Exception) { }
        }
        return Task.CompletedTask;
    }
}
