using System.Net;
using System.Net.Sockets;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// L14-1: Wake-on-LAN 핸들러. "wol" 프리픽스로 사용합니다.
///
/// 예: wol                         → 저장된 호스트 목록
///     wol AA:BB:CC:DD:EE:FF       → 매직 패킷 전송
///     wol AA-BB-CC-DD-EE-FF       → 대시 구분자도 지원
///     wol AABBCCDDEEFF            → 구분자 없는 형식
///     wol save PC-1 AA:BB:CC:DD:EE:FF  → 호스트 저장
///     wol delete PC-1             → 저장 항목 삭제
/// Enter → 매직 패킷 전송.
/// </summary>
public class WolHandler : IActionHandler
{
    public string? Prefix => "wol";

    public PluginMetadata Metadata => new(
        "WoL",
        "Wake-on-LAN — 매직 패킷 전송 · 호스트 관리",
        "1.0",
        "AX");

    private static readonly string StorePath = System.IO.Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "AxCopilot", "wol_hosts.json");

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

        if (string.IsNullOrWhiteSpace(q))
        {
            if (hosts.Count == 0)
            {
                items.Add(new LauncherItem("Wake-on-LAN",
                    "예: wol AA:BB:CC:DD:EE:FF  /  wol save 이름 AA:BB:CC:...",
                    null, null, Symbol: "\uE823"));
            }
            else
            {
                items.Add(new LauncherItem($"저장된 호스트  {hosts.Count}개",
                    "Enter → 매직 패킷 전송", null, null, Symbol: "\uE823"));
                foreach (var h in hosts)
                    items.Add(MakeHostItem(h));
            }
            items.Add(new LauncherItem("wol save 이름 MAC",   "호스트 저장",    null, null, Symbol: "\uE823"));
            items.Add(new LauncherItem("wol AA:BB:CC:…",       "직접 전송",      null, null, Symbol: "\uE823"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

        switch (sub)
        {
            case "save":
            case "add":
            {
                if (parts.Length < 3)
                {
                    items.Add(new LauncherItem("형식 오류", "예: wol save PC-이름 AA:BB:CC:DD:EE:FF", null, null, Symbol: "\uE783"));
                    break;
                }
                var name = parts[1];
                var mac  = parts[2];
                if (!TryParseMac(mac, out var macBytes))
                {
                    items.Add(new LauncherItem("MAC 형식 오류", $"'{mac}'은 유효한 MAC 주소가 아닙니다", null, null, Symbol: "\uE783"));
                    break;
                }
                items.Add(new LauncherItem(
                    $"저장: {name}  ({mac})",
                    "Enter → 저장",
                    null, ("save", $"{name}|{mac}"), Symbol: "\uE823"));
                break;
            }

            case "delete":
            case "del":
            case "remove":
            {
                var target = parts.Length > 1 ? string.Join(" ", parts.Skip(1)) : "";
                var found  = hosts.FirstOrDefault(h =>
                    h.Name.Equals(target, StringComparison.OrdinalIgnoreCase));
                if (found == null)
                    items.Add(new LauncherItem("없는 항목", $"'{target}'을 찾을 수 없습니다", null, null, Symbol: "\uE783"));
                else
                    items.Add(new LauncherItem($"삭제: {found.Name}", found.Mac, null, ("delete", found.Name), Symbol: "\uE74D"));
                break;
            }

            default:
            {
                // MAC 주소 직접 입력
                if (TryParseMac(q, out _))
                {
                    items.Add(new LauncherItem(
                        $"매직 패킷 전송: {q}",
                        "Enter → 브로드캐스트 전송 (255.255.255.255:9)",
                        null, ("send", q), Symbol: "\uE823"));
                }
                // 저장된 호스트 이름 검색
                else
                {
                    var filtered = hosts.Where(h =>
                        h.Name.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();
                    if (filtered.Count == 0)
                        items.Add(new LauncherItem("결과 없음",
                            $"'{q}' 항목 없음. MAC 형식: AA:BB:CC:DD:EE:FF", null, null, Symbol: "\uE946"));
                    else
                        foreach (var h in filtered)
                            items.Add(MakeHostItem(h));
                }
                break;
            }
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data)
        {
            case ("send", string mac):
                SendMagicPacket(mac);
                break;

            case ("wake", string mac):
                SendMagicPacket(mac);
                break;

            case ("save", string data):
            {
                var idx   = data.IndexOf('|');
                var name  = data[..idx];
                var mac   = data[(idx + 1)..];
                var hosts = LoadHosts();
                hosts.RemoveAll(h => h.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
                hosts.Add(new WolHost { Name = name, Mac = mac });
                SaveHosts(hosts);
                NotificationService.Notify("WoL", $"'{name}' ({mac}) 저장됨");
                break;
            }

            case ("delete", string name):
            {
                var hosts = LoadHosts();
                hosts.RemoveAll(h => h.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
                SaveHosts(hosts);
                NotificationService.Notify("WoL", $"'{name}' 삭제됨");
                break;
            }

            case ("copy", string text):
                try
                {
                    System.Windows.Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(text));
                    NotificationService.Notify("WoL", "클립보드에 복사했습니다.");
                }
                catch { /* 비핵심 */ }
                break;
        }
        return Task.CompletedTask;
    }

    // ── 매직 패킷 전송 ────────────────────────────────────────────────────────

    private static void SendMagicPacket(string mac)
    {
        if (!TryParseMac(mac, out var macBytes))
        {
            NotificationService.Notify("WoL", $"MAC 형식 오류: {mac}");
            return;
        }

        // 매직 패킷: 0xFF × 6 + MAC × 16
        var packet = new byte[102];
        for (var i = 0; i < 6; i++)
            packet[i] = 0xFF;
        for (var i = 1; i <= 16; i++)
            Array.Copy(macBytes, 0, packet, i * 6, 6);

        try
        {
            using var udp = new UdpClient();
            udp.EnableBroadcast = true;
            udp.Send(packet, packet.Length, new IPEndPoint(IPAddress.Broadcast, 9));
            // 포트 7도 함께 전송 (일부 장치)
            udp.Send(packet, packet.Length, new IPEndPoint(IPAddress.Broadcast, 7));
            NotificationService.Notify("WoL", $"매직 패킷 전송됨 → {mac}");
        }
        catch (Exception ex)
        {
            NotificationService.Notify("WoL", $"전송 실패: {ex.Message}");
        }
    }

    // ── 파싱·저장 헬퍼 ────────────────────────────────────────────────────────

    private static bool TryParseMac(string s, out byte[] bytes)
    {
        bytes = [];
        s = s.Trim().Replace(":", "").Replace("-", "").Replace(".", "");
        if (s.Length != 12) return false;
        try
        {
            bytes = Enumerable.Range(0, 6)
                .Select(i => Convert.ToByte(s.Substring(i * 2, 2), 16))
                .ToArray();
            return true;
        }
        catch { return false; }
    }

    private static LauncherItem MakeHostItem(WolHost h) =>
        new(h.Name, h.Mac, null, ("wake", h.Mac), Symbol: "\uE823");

    // ── 영속 스토리지 ─────────────────────────────────────────────────────────

    private class WolHost
    {
        [JsonPropertyName("name")] public string Name { get; set; } = "";
        [JsonPropertyName("mac")]  public string Mac  { get; set; } = "";
    }

    private static List<WolHost> LoadHosts()
    {
        try
        {
            if (!System.IO.File.Exists(StorePath)) return new();
            var json = System.IO.File.ReadAllText(StorePath);
            return JsonSerializer.Deserialize<List<WolHost>>(json) ?? new();
        }
        catch { return new(); }
    }

    private static void SaveHosts(List<WolHost> hosts)
    {
        try
        {
            System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(StorePath)!);
            System.IO.File.WriteAllText(StorePath,
                JsonSerializer.Serialize(hosts, new JsonSerializerOptions { WriteIndented = true }));
        }
        catch { /* 비핵심 */ }
    }
}
