using System.IO;
using System.Text;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// L12-2: Windows hosts 파일 관리 핸들러. "hosts" 프리픽스로 사용합니다.
///
/// 예: hosts                → 현재 hosts 파일 항목 목록
///     hosts search dev     → "dev" 포함 항목 필터
///     hosts open           → hosts 파일을 메모장으로 열기
///     hosts copy           → 전체 hosts 내용 클립보드 복사
/// Enter → 해당 항목을 클립보드에 복사.
/// </summary>
public class HostsHandler : IActionHandler
{
    public string? Prefix => "hosts";

    public PluginMetadata Metadata => new(
        "Hosts",
        "Windows hosts 파일 뷰어 — 항목 조회 · 검색 · 복사",
        "1.0",
        "AX");

    private static readonly string HostsPath =
        Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System),
                     @"drivers\etc\hosts");

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

        var entries = ReadHostsEntries();

        if (string.IsNullOrWhiteSpace(q))
        {
            var activeCount   = entries.Count(e => !e.IsComment);
            var commentCount  = entries.Count(e => e.IsComment && e.IsDisabledEntry);

            items.Add(new LauncherItem(
                $"hosts 파일  활성 {activeCount}개" + (commentCount > 0 ? $"  ·  비활성 {commentCount}개" : ""),
                HostsPath,
                null,
                ("copy_path", HostsPath),
                Symbol: "\uE8D2"));

            items.Add(new LauncherItem("파일 열기 (메모장)", HostsPath, null, ("open", HostsPath), Symbol: "\uE8A5"));
            items.Add(new LauncherItem("전체 내용 복사", $"{entries.Count}줄", null, ("copy_all", ""), Symbol: "\uE8A5"));

            // 유효 항목 목록
            foreach (var e in entries.Where(e => !e.IsComment).Take(20))
                items.Add(MakeEntryItem(e));

            // 비활성 항목 (주석 처리된 IP 항목)
            var disabled = entries.Where(e => e.IsDisabledEntry).Take(5).ToList();
            if (disabled.Count > 0)
            {
                items.Add(new LauncherItem($"── 비활성 항목 {disabled.Count}개 ──", "", null, null, Symbol: "\uE8D2"));
                foreach (var e in disabled)
                    items.Add(MakeEntryItem(e));
            }

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

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

        switch (sub)
        {
            case "open":
                items.Add(new LauncherItem("메모장으로 열기", HostsPath, null, ("open", HostsPath), Symbol: "\uE8A5"));
                break;

            case "copy":
            case "copy_all":
            {
                var content = ReadHostsRaw();
                items.Add(new LauncherItem("전체 내용 복사", $"{content.Split('\n').Length}줄  · Enter 복사",
                    null, ("copy", content), Symbol: "\uE8A5"));
                break;
            }

            case "search":
            case "find":
            {
                var keyword = parts.Length > 1 ? parts[1].ToLowerInvariant() : "";
                if (string.IsNullOrWhiteSpace(keyword))
                {
                    items.Add(new LauncherItem("검색어 입력", "예: hosts search dev", null, null, Symbol: "\uE783"));
                    break;
                }
                var filtered = entries.Where(e =>
                    e.Hostname.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
                    e.IpAddress.Contains(keyword, StringComparison.OrdinalIgnoreCase)).ToList();

                if (filtered.Count == 0)
                    items.Add(new LauncherItem("결과 없음", $"'{keyword}' 항목 없음", null, null, Symbol: "\uE946"));
                else
                    foreach (var e in filtered.Take(20))
                        items.Add(MakeEntryItem(e));
                break;
            }

            default:
            {
                // 검색어로 처리
                var keyword = q.ToLowerInvariant();
                var filtered = entries.Where(e =>
                    e.Hostname.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
                    e.IpAddress.Contains(keyword, StringComparison.OrdinalIgnoreCase)).ToList();

                if (filtered.Count == 0)
                    items.Add(new LauncherItem("결과 없음", $"'{q}' 항목 없음", null, null, Symbol: "\uE946"));
                else
                    foreach (var e in filtered.Take(20))
                        items.Add(MakeEntryItem(e));
                break;
            }
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data)
        {
            case ("copy", string text):
                try
                {
                    System.Windows.Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(text));
                    NotificationService.Notify("Hosts", "클립보드에 복사했습니다.");
                }
                catch { /* 비핵심 */ }
                break;

            case ("copy_path", string path):
                try
                {
                    System.Windows.Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(path));
                    NotificationService.Notify("Hosts", "경로가 복사되었습니다.");
                }
                catch { /* 비핵심 */ }
                break;

            case ("copy_all", _):
                try
                {
                    var content = ReadHostsRaw();
                    System.Windows.Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(content));
                    NotificationService.Notify("Hosts", $"hosts 파일 내용 복사됨 ({content.Split('\n').Length}줄)");
                }
                catch { /* 비핵심 */ }
                break;

            case ("open", string path):
                try
                {
                    System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
                    {
                        FileName        = "notepad.exe",
                        Arguments       = $"\"{path}\"",
                        UseShellExecute = false,
                    });
                }
                catch (Exception ex)
                {
                    NotificationService.Notify("Hosts", $"열기 실패: {ex.Message}");
                }
                break;
        }
        return Task.CompletedTask;
    }

    // ── hosts 파일 파서 ───────────────────────────────────────────────────────

    private record HostsEntry(string IpAddress, string Hostname, string RawLine,
                               bool IsComment, bool IsDisabledEntry);

    private static List<HostsEntry> ReadHostsEntries()
    {
        var result = new List<HostsEntry>();
        string[] lines;
        try   { lines = File.ReadAllLines(HostsPath, Encoding.UTF8); }
        catch { return result; }

        foreach (var rawLine in lines)
        {
            var line = rawLine.Trim();
            if (string.IsNullOrWhiteSpace(line)) continue;

            // 순수 주석 (# 으로 시작, IP 없음)
            if (line.StartsWith('#'))
            {
                // 비활성 IP 항목인지 확인 (예: "# 127.0.0.1 example.com")
                var inner = line[1..].Trim();
                if (TryParseIpEntry(inner, out var disIp, out var disHost))
                {
                    result.Add(new HostsEntry(disIp, disHost, rawLine, true, true));
                }
                // 순수 주석은 목록에서 제외
                continue;
            }

            // IP 항목 (인라인 주석 포함 가능)
            var withoutComment = line.Contains('#') ? line[..line.IndexOf('#')].Trim() : line;
            if (TryParseIpEntry(withoutComment, out var ip, out var host))
            {
                result.Add(new HostsEntry(ip, host, rawLine, false, false));
            }
        }
        return result;
    }

    private static bool TryParseIpEntry(string line, out string ip, out string host)
    {
        ip = host = "";
        var parts = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
        if (parts.Length < 2) return false;

        // 첫 토큰이 IP 주소 형태인지 간단히 확인
        if (!System.Net.IPAddress.TryParse(parts[0], out _)) return false;
        ip   = parts[0];
        host = parts[1];
        return true;
    }

    private static string ReadHostsRaw()
    {
        try   { return File.ReadAllText(HostsPath, Encoding.UTF8); }
        catch { return "(hosts 파일을 읽을 수 없습니다)"; }
    }

    private static LauncherItem MakeEntryItem(HostsEntry e)
    {
        var prefix  = e.IsComment ? "# " : "";
        var icon    = e.IsComment ? "\uE946" : "\uE8D2";
        var subtitle = e.IsComment ? "비활성 항목" : e.IpAddress;

        return new LauncherItem(
            $"{prefix}{e.Hostname}",
            subtitle,
            null,
            ("copy", $"{e.IpAddress}\t{e.Hostname}"),
            Symbol: icon);
    }
}
