using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// L16-1: ping·tracert 빠른 실행 핸들러. "ping" 프리픽스로 사용합니다.
///
/// 예: ping 8.8.8.8            → ping 결과 (4회)
///     ping google.com         → 도메인 ping
///     ping trace 8.8.8.8      → tracert 실행
///     ping local              → 로컬 네트워크 어댑터 정보
///     ping scan 192.168.1.0   → 간단 네트워크 스캔 (1~254)
/// Enter → 결과 복사 또는 외부 터미널 실행.
/// 사내 모드: 외부 IP/도메인 ping 차단.
/// </summary>
public class PingHandler : IActionHandler
{
    public string? Prefix => "ping";

    public PluginMetadata Metadata => new(
        "Ping",
        "ping·tracert 빠른 실행 — 네트워크 연결 확인·경로 추적",
        "1.0",
        "AX");

    private static readonly string[] QuickTargets =
        ["localhost", "8.8.8.8", "1.1.1.1", "google.com", "192.168.1.1"];

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

        if (string.IsNullOrWhiteSpace(q))
        {
            items.Add(new LauncherItem("ping / tracert 실행기",
                "예: ping 8.8.8.8  /  ping trace 192.168.1.1  /  ping local  /  ping scan 192.168.1",
                null, null, Symbol: "\uE968"));
            items.Add(new LauncherItem("── 빠른 대상 ──", "", null, null, Symbol: "\uE968"));
            foreach (var t in QuickTargets)
                items.Add(new LauncherItem($"ping {t}", t, null, ("ping", t), Symbol: "\uE968"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        var parts = q.Split(' ', StringSplitOptions.RemoveEmptyEntries);
        var sub   = parts[0].ToLowerInvariant();

        // local → 로컬 어댑터 정보
        if (sub == "local" || sub == "lo")
        {
            items.AddRange(BuildLocalNetworkItems());
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // trace / tracert / traceroute
        if (sub is "trace" or "tracert" or "traceroute")
        {
            var target = parts.Length > 1 ? parts[1] : "";
            if (string.IsNullOrWhiteSpace(target))
            {
                items.Add(new LauncherItem("대상 주소 입력", "예: ping trace 8.8.8.8", null, null, Symbol: "\uE783"));
            }
            else
            {
                var blocked = CheckInternalMode(target);
                if (blocked != null) { items.Add(blocked); return Task.FromResult<IEnumerable<LauncherItem>>(items); }
                items.Add(new LauncherItem($"tracert {target}", "Enter → 터미널에서 tracert 실행",
                    null, ("tracert", target), Symbol: "\uE968"));
                items.Add(new LauncherItem("터미널 실행", $"tracert {target}",
                    null, ("tracert", target), Symbol: "\uE968"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // scan → 간단 스캔 (비동기 결과는 실행 시 터미널)
        if (sub == "scan")
        {
            var network = parts.Length > 1 ? parts[1] : "192.168.1";
            items.Add(new LauncherItem($"네트워크 스캔: {network}.1~254",
                "Enter → 터미널에서 ping 스캔 스크립트 실행",
                null, ("scan", network), Symbol: "\uE968"));
            items.Add(new LauncherItem("팁", "결과가 많을 수 있습니다 — 터미널에서 확인하세요",
                null, null, Symbol: "\uE946"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 직접 ping 대상
        var host = parts[0];
        var blocked2 = CheckInternalMode(host);
        if (blocked2 != null) { items.Add(blocked2); return Task.FromResult<IEnumerable<LauncherItem>>(items); }

        items.Add(new LauncherItem($"ping {host}",
            "Enter → 비동기 ping (4회) 실행",
            null, ("ping", host), Symbol: "\uE968"));
        items.Add(new LauncherItem($"tracert {host}",
            "Enter → 터미널에서 tracert 실행",
            null, ("tracert", host), Symbol: "\uE968"));
        items.Add(new LauncherItem($"ping 연속 {host}",
            "ping -t (무한 반복) — 터미널",
            null, ("ping_t", host), Symbol: "\uE968"));

        // 즉시 1회 ping 시도
        var pingResult = TryPingOnce(host);
        if (pingResult != null)
        {
            items.Insert(0, pingResult);
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data)
        {
            case ("ping", string host):
                RunInTerminal($"ping {host}");
                break;

            case ("ping_t", string host):
                RunInTerminal($"ping -t {host}");
                break;

            case ("tracert", string host):
                RunInTerminal($"tracert {host}");
                break;

            case ("scan", string network):
                // PowerShell로 간단 스캔
                var ps = $"1..254 | ForEach-Object {{ $ip = '{network}.$_'; if (Test-Connection $ip -Count 1 -Quiet -TimeoutSeconds 1) {{ Write-Host \"$ip is UP\" }} }}; Read-Host 'Press Enter'";
                RunInTerminal($"powershell -NoExit -Command \"{ps}\"", usePs: true);
                break;

            case ("copy", string text):
                try
                {
                    System.Windows.Application.Current.Dispatcher.Invoke(
                        () => Clipboard.SetText(text));
                    NotificationService.Notify("Ping", "복사됨");
                }
                catch { /* 비핵심 */ }
                break;
        }
        return Task.CompletedTask;
    }

    // ── 헬퍼 ─────────────────────────────────────────────────────────────────

    private static List<LauncherItem> BuildLocalNetworkItems()
    {
        var items = new List<LauncherItem>();
        try
        {
            var ifaces = NetworkInterface.GetAllNetworkInterfaces()
                .Where(n => n.OperationalStatus == OperationalStatus.Up &&
                            n.NetworkInterfaceType != NetworkInterfaceType.Loopback)
                .ToList();

            items.Add(new LauncherItem($"로컬 네트워크 어댑터  {ifaces.Count}개", "", null, null, Symbol: "\uE968"));

            foreach (var iface in ifaces)
            {
                var ipProps = iface.GetIPProperties();
                var ipv4    = ipProps.UnicastAddresses
                    .FirstOrDefault(a => a.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
                var gateway = ipProps.GatewayAddresses.FirstOrDefault()?.Address?.ToString() ?? "없음";

                if (ipv4 == null) continue;

                var ip      = ipv4.Address.ToString();
                var mask    = ipv4.IPv4Mask.ToString();
                var label   = $"{iface.Name}  {ip}";
                var sub2    = $"넷마스크 {mask}  ·  게이트웨이 {gateway}";
                items.Add(new LauncherItem(label, sub2, null, ("copy", ip), Symbol: "\uE968"));
            }

            // 외부 IP 안내 (사외 모드에서만)
            var settings = (System.Windows.Application.Current as App)?.SettingsService?.Settings;
            if (settings?.InternalModeEnabled == false)
                items.Add(new LauncherItem("외부 IP 조회", "ping trace 8.8.8.8 으로 경로 확인",
                    null, null, Symbol: "\uE968"));
        }
        catch (Exception ex)
        {
            items.Add(new LauncherItem("네트워크 정보 조회 오류", ex.Message, null, null, Symbol: "\uE783"));
        }
        return items;
    }

    private static LauncherItem? TryPingOnce(string host)
    {
        try
        {
            using var p = new Ping();
            var reply   = p.Send(host, 1000);
            if (reply.Status == IPStatus.Success)
            {
                var label = $"✓ 응답  {reply.RoundtripTime}ms";
                return new LauncherItem(label, $"TTL {reply.Options?.Ttl ?? 0}  ·  {host}",
                    null, ("copy", $"{reply.RoundtripTime}ms"), Symbol: "\uE968");
            }
            return new LauncherItem($"✗ 응답 없음 ({reply.Status})", host, null, null, Symbol: "\uE783");
        }
        catch
        {
            return null; // 오류 시 무시
        }
    }

    private static LauncherItem? CheckInternalMode(string host)
    {
        var settings = (System.Windows.Application.Current as App)?.SettingsService?.Settings;
        if (settings?.InternalModeEnabled != true) return null;

        // 내부 주소는 허용
        if (host.StartsWith("192.168.", StringComparison.Ordinal) ||
            host.StartsWith("10.",       StringComparison.Ordinal) ||
            host.StartsWith("172.",      StringComparison.Ordinal) ||
            host.Equals("localhost",     StringComparison.OrdinalIgnoreCase) ||
            host.StartsWith("127.",      StringComparison.Ordinal))
            return null;

        if (IPAddress.TryParse(host, out _))
            return null; // IP 주소 → 내부로 간주 허용

        return new LauncherItem("사내 모드 — 외부 도메인 차단",
            "사외 모드에서 외부 주소 ping 가능. 설정에서 변경하세요.",
            null, null, Symbol: "\uE783");
    }

    private static void RunInTerminal(string cmd, bool usePs = false)
    {
        try
        {
            var wtPath = FindExe("wt.exe");
            if (wtPath != null && !usePs)
            {
                System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
                {
                    FileName = wtPath, Arguments = $"cmd /K {cmd}", UseShellExecute = false,
                });
            }
            else
            {
                System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
                {
                    FileName = usePs ? "powershell" : "cmd",
                    Arguments = usePs ? $"-NoExit -Command \"{cmd}\"" : $"/K {cmd}",
                    UseShellExecute = true,
                });
            }
        }
        catch { /* 비핵심 */ }
    }

    private static string? FindExe(string name)
    {
        foreach (var dir in (Environment.GetEnvironmentVariable("PATH") ?? "").Split(';'))
        {
            var full = System.IO.Path.Combine(dir.Trim(), name);
            if (System.IO.File.Exists(full)) return full;
        }
        return null;
    }
}
