using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;
using AxCopilot.Views;

namespace AxCopilot.Handlers;

/// <summary>
/// 시스템 정보를 표시합니다. "info" 프리픽스로 사용합니다.
/// 예: info           → 전체 시스템 정보 목록
///     info ip        → IP 주소
///     info battery   → 배터리 상태
///     info uptime    → 시스템 가동 시간
///     info volume    → 볼륨 수준
/// </summary>
public partial class SystemInfoHandler : IActionHandler
{
    public string? Prefix => "info";

    public PluginMetadata Metadata => new(
        "SystemInfo",
        "시스템 정보 — IP, 배터리, 볼륨, 가동시간 등",
        "1.0",
        "AX");

    // ─── P/Invoke ────────────────────────────────────────────────────────────

    [DllImport("winmm.dll")]
    private static extern int waveOutGetVolume(IntPtr hwo, out uint dwVolume);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    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;
    }

    // CPU 카운터: 앱 시작 시 백그라운드에서 사전 초기화 (UI 스레드 차단 방지)
    private static volatile PerformanceCounter? _cpuCounter;
    private static float               _cpuCached;
    private static DateTime            _cpuUpdated = DateTime.MinValue;
    private static readonly object     _cpuLock = new();
    static SystemInfoHandler()
    {
        // 백그라운드에서 PerformanceCounter 초기화 (1~3초 소요, UI 스레드 차단 방지)
        _ = Task.Run(() =>
        {
            try
            {
                var counter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
                counter.NextValue(); // 첫 호출은 항상 0 → 초기화만
                _cpuCounter = counter;
            }
            catch (Exception) { /* PerformanceCounter 미지원 환경 */ }
        });
    }

    private static float GetCpuUsage()
    {
        try
        {
            var counter = _cpuCounter;
            if (counter == null) return -1; // 아직 초기화 중
            lock (_cpuLock)
            {
                if ((DateTime.Now - _cpuUpdated).TotalMilliseconds > 800)
                {
                    _cpuCached  = counter.NextValue();
                    _cpuUpdated = DateTime.Now;
                }
                return _cpuCached;
            }
        }
        catch (Exception) { return -1; }
    }

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

        try
        {
            // 어떤 카테고리를 보여줄지 결정
            bool showAll  = string.IsNullOrEmpty(q);
            bool showIp   = showAll || q.Contains("ip")      || q.Contains("네트워크") || q.Contains("network");
            bool showBat  = showAll || q.Contains("bat")     || q.Contains("배터리")   || q.Contains("battery");
            bool showVol  = showAll || q.Contains("vol")     || q.Contains("볼륨")     || q.Contains("volume");
            bool showUp   = showAll || q.Contains("up")      || q.Contains("가동")     || q.Contains("uptime");
            bool showSys  = showAll || q.Contains("sys")     || q.Contains("시스템")   || q.Contains("system")
                                    || q.Contains("host")    || q.Contains("호스트")   || q.Contains("os");
            bool showUser = showAll || q.Contains("user")    || q.Contains("사용자");
            bool showCpu  = showAll || q.Contains("cpu")     || q.Contains("프로세서") || q.Contains("processor");
            bool showRam  = showAll || q.Contains("ram")     || q.Contains("메모리")   || q.Contains("memory");
            bool showDisk = showAll || q.Contains("disk")    || q.Contains("디스크")   || q.Contains("storage") || q.Contains("저장");
            bool showGfx  = showAll || q.Contains("screen")  || q.Contains("화면")     || q.Contains("resolution") || q.Contains("display");

            // ─── 호스트 / OS / 사용자 ────────────────────────────────────────
            if (showSys)
            {
                items.Add(new LauncherItem(
                    $"컴퓨터: {Environment.MachineName}",
                    $"OS: {GetOsVersion()}  ·  Enter로 시스템 정보 열기",
                    null,
                    new InfoAction("shell", "msinfo32"),
                    Symbol: Symbols.Computer));
            }

            if (showUser)
            {
                var user = $"{Environment.UserDomainName}\\{Environment.UserName}";
                items.Add(new LauncherItem(
                    $"사용자: {Environment.UserName}",
                    $"{user}  ·  Enter로 사용자 계정 설정 열기",
                    null,
                    new InfoAction("shell", "netplwiz"),
                    Symbol: Symbols.Person));
            }

            // ─── IP 주소 ────────────────────────────────────────────────────
            if (showIp)
            {
                var localIp = GetLocalIpAddress();
                if (localIp != null)
                {
                    items.Add(new LauncherItem(
                        $"로컬 IP: {localIp}",
                        "LAN / Wi-Fi 주소  ·  Enter로 네트워크 설정 열기",
                        null,
                        new InfoAction("ms_settings", "ms-settings:network"),
                        Symbol: Symbols.Network));
                }

                var gateway = GetDefaultGateway();
                if (gateway != null)
                {
                    items.Add(new LauncherItem(
                        $"게이트웨이: {gateway}",
                        "기본 게이트웨이  ·  Enter로 네트워크 설정 열기",
                        null,
                        new InfoAction("ms_settings", "ms-settings:network"),
                        Symbol: Symbols.Network));
                }
            }

            // ─── 배터리 ────────────────────────────────────────────────────
            if (showBat)
            {
                var batItem = GetBatteryItem();
                if (batItem != null) items.Add(batItem);
            }

            // ─── 볼륨 ──────────────────────────────────────────────────────
            if (showVol)
            {
                var volItem = GetVolumeItem();
                if (volItem != null) items.Add(volItem);
            }

            // ─── 가동 시간 / 부팅 시간 / 로그인 시간 ──────────────────────────
            if (showUp)
            {
                // 부팅 시간: System 프로세스(PID 4) StartTime — TickCount64보다 정확
                // (절전·최대 절전 후에도 실제 부팅 시각을 유지)
                DateTime? bootTime = null;
                try { bootTime = Process.GetProcessById(4).StartTime; }
                catch { }

                // 폴백: TickCount64 (PID 4 접근 불가 환경)
                if (bootTime == null)
                {
                    var ticks = TimeSpan.FromMilliseconds(Environment.TickCount64);
                    bootTime = DateTime.Now - ticks;
                }

                var uptime    = DateTime.Now - bootTime.Value;
                var uptimeStr = FormatUptime(uptime);

                items.Add(MakeItem(
                    $"가동 시간: {uptimeStr}",
                    $"부팅: {bootTime.Value:MM/dd HH:mm:ss}",
                    $"부팅 {bootTime.Value:yyyy-MM-dd HH:mm:ss}  가동 {uptimeStr}",
                    Symbols.Clock));

                // 로그인 시간: 현재 세션의 explorer.exe 최초 시작 시각
                try
                {
                    var sessionId = Process.GetCurrentProcess().SessionId;
                    var loginProc = Process.GetProcessesByName("explorer")
                        .Where(p => p.SessionId == sessionId)
                        .OrderBy(p => p.StartTime)
                        .FirstOrDefault();

                    if (loginProc != null)
                    {
                        var loginTime    = loginProc.StartTime;
                        var loginElapsed = FormatUptime(DateTime.Now - loginTime);
                        var bootToLogin  = loginTime - bootTime.Value;
                        items.Add(MakeItem(
                            $"로그인: {loginTime:HH:mm:ss}  ({loginElapsed} 전)",
                            $"부팅→로그인 소요: {(int)bootToLogin.TotalSeconds}초",
                            $"로그인 {loginTime:yyyy-MM-dd HH:mm:ss}",
                            Symbols.Person));
                    }
                }
                catch { /* explorer 없는 환경 무시 */ }
            }

            // ─── CPU 사용률 ────────────────────────────────────────────────
            if (showCpu)
            {
                var cpu = GetCpuUsage();
                var cpuTitle = cpu < 0 ? "CPU: 측정 중…" : $"CPU: {(int)cpu}%";
                var cpuProc  = GetProcessorName();
                items.Add(new LauncherItem(
                    cpuTitle,
                    (string.IsNullOrEmpty(cpuProc) ? "전체 CPU 사용률" : cpuProc) + "  ·  Enter로 리소스 모니터 열기",
                    null,
                    new InfoAction("resource_mon"),
                    Symbol: Symbols.Processor));
            }

            // ─── 메모리 (RAM) ──────────────────────────────────────────────
            if (showRam)
            {
                var mem = new MEMORYSTATUSEX { dwLength = (uint)Marshal.SizeOf<MEMORYSTATUSEX>() };
                if (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(
                        $"RAM: {usedGb:F1} / {totalGb:F1} GB  ({pct}%)",
                        $"사용 중: {usedGb:F1} GB  ·  여유: {(mem.ullAvailPhys / 1024.0 / 1024 / 1024):F1} GB  ·  Enter로 리소스 모니터 열기",
                        null,
                        new InfoAction("resource_mon"),
                        Symbol: Symbols.Memory));
                }
            }

            // ─── 디스크 ────────────────────────────────────────────────────
            if (showDisk)
            {
                foreach (var drive in System.IO.DriveInfo.GetDrives()
                    .Where(d => d.IsReady && d.DriveType == System.IO.DriveType.Fixed))
                {
                    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);
                    var label   = string.IsNullOrWhiteSpace(drive.VolumeLabel) ? drive.Name.TrimEnd('\\') : drive.VolumeLabel;
                    items.Add(new LauncherItem(
                        $"드라이브 {drive.Name.TrimEnd('\\')}  ({label})  — {usedGb:F0} / {totalGb:F0} GB  ({pct}%)",
                        $"여유 공간: {freeGb:F1} GB  ·  Enter로 탐색기 열기",
                        null,
                        new InfoAction("open_drive", drive.RootDirectory.FullName),
                        Symbol: Symbols.Storage));
                }
            }

            // ─── 화면 해상도 ───────────────────────────────────────────────
            if (showGfx)
            {
                var screen = System.Windows.SystemParameters.PrimaryScreenWidth;
                var screenH = System.Windows.SystemParameters.PrimaryScreenHeight;
                items.Add(new LauncherItem(
                    $"화면: {(int)screen} × {(int)screenH}",
                    "기본 모니터 해상도  ·  Enter로 디스플레이 설정 열기",
                    null,
                    new InfoAction("ms_settings", "ms-settings:display"),
                    Symbol: Symbols.Computer));
            }
        }
        catch (Exception ex)
        {
            LogService.Warn($"시스템 정보 조회 오류: {ex.Message}");
            items.Add(new LauncherItem("시스템 정보 조회 실패", ex.Message, null, null, Symbol: Symbols.Error));
        }

        if (items.Count == 0)
        {
            items.Add(new LauncherItem(
                "시스템 정보 없음",
                "ip · battery · volume · uptime · system 키워드로 검색하세요",
                null, null, Symbol: Symbols.Info));
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is not InfoAction action) return Task.CompletedTask;

        switch (action.Type)
        {
            case "copy":
                // 클립보드에 복사
                if (!string.IsNullOrWhiteSpace(action.Payload))
                {
                    try
                    {
                        Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(action.Payload));
                        LogService.Info($"클립보드 복사: {action.Payload}");
                    }
                    catch (Exception ex) { LogService.Warn($"클립보드 복사 실패: {ex.Message}"); }
                }
                break;

            case "open_drive":
                // 탐색기로 드라이브 열기
                if (!string.IsNullOrWhiteSpace(action.Payload))
                {
                    try
                    {
                        Process.Start(new ProcessStartInfo("explorer.exe", action.Payload)
                            { UseShellExecute = true });
                    }
                    catch (Exception ex) { LogService.Warn($"드라이브 열기 실패: {ex.Message}"); }
                }
                break;

            case "resource_mon":
                // CPU/RAM 실시간 모니터 창 열기
                Application.Current.Dispatcher.Invoke(() =>
                {
                    var existing = Application.Current.Windows
                        .OfType<ResourceMonitorWindow>().FirstOrDefault();
                    if (existing != null) { existing.Activate(); return; }
                    new ResourceMonitorWindow().Show();
                });
                break;

            case "shell":
                // 셸 명령 실행 (msinfo32, netplwiz 등)
                if (!string.IsNullOrWhiteSpace(action.Payload))
                {
                    try
                    {
                        Process.Start(new ProcessStartInfo(action.Payload) { UseShellExecute = true });
                    }
                    catch (Exception ex) { LogService.Warn($"셸 명령 실행 실패: {ex.Message}"); }
                }
                break;

            case "ms_settings":
                // Windows 설정 URI (ms-settings:network, ms-settings:display 등)
                if (!string.IsNullOrWhiteSpace(action.Payload))
                {
                    try
                    {
                        Process.Start(new ProcessStartInfo(action.Payload) { UseShellExecute = true });
                    }
                    catch (Exception ex) { LogService.Warn($"설정 열기 실패: {ex.Message}"); }
                }
                break;
        }
        return Task.CompletedTask;
    }

    // ─── 액션 데이터 태그 ────────────────────────────────────────────────────

    /// <summary>info 항목에 의미 있는 동작을 부여하기 위한 태그</summary>
    internal sealed record InfoAction(string Type, string? Payload = null);
    // Type: "copy"          → 클립보드 복사 (Payload = 복사할 텍스트)
    //       "open_drive"    → 탐색기로 드라이브 열기 (Payload = 드라이브 루트)
    //       "resource_mon"  → CPU/RAM 실시간 모니터 창 열기
    //       "shell"         → 셸 명령 실행 (Payload = 명령)
    //       "ms_settings"   → ms-settings: URI 열기 (Payload = URI)

}
