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

namespace AxCopilot.Handlers;

/// <summary>
/// L16-2: Docker 컨테이너·이미지 조회 핸들러. "docker" 프리픽스로 사용합니다.
///
/// 예: docker                  → 실행 중 컨테이너 목록
///     docker all              → 모든 컨테이너 (중지 포함)
///     docker images           → 로컬 이미지 목록
///     docker ps               → 컨테이너 목록 (docker ps 동일)
///     docker stop <name>      → 컨테이너 중지
///     docker start <name>     → 컨테이너 시작
///     docker logs <name>      → 컨테이너 로그 (터미널)
///     docker shell <name>     → 컨테이너 shell 접속
/// Enter → 명령 실행 또는 컨테이너 ID 복사.
/// </summary>
public class DockerHandler : IActionHandler
{
    public string? Prefix => "docker";

    public PluginMetadata Metadata => new(
        "Docker",
        "Docker 컨테이너·이미지 조회 — 시작·중지·로그·쉘",
        "1.0",
        "AX");

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

        if (!IsDockerAvailable())
        {
            items.Add(new LauncherItem("Docker를 찾을 수 없습니다",
                "Docker Desktop이 설치되어 있는지 확인하세요", null, null, Symbol: "\uE756"));
            items.Add(new LauncherItem("Docker Desktop 설치",
                "https://www.docker.com/products/docker-desktop",
                null, ("open_url", "https://www.docker.com/products/docker-desktop"), Symbol: "\uE756"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        if (string.IsNullOrWhiteSpace(q))
        {
            var containers = GetContainers(running: true);
            items.Add(new LauncherItem(
                $"실행 중 컨테이너  {containers.Count}개",
                "docker ps  /  docker all  /  docker images",
                null, null, Symbol: "\uE756"));

            if (containers.Count == 0)
                items.Add(new LauncherItem("실행 중인 컨테이너 없음", "docker all → 전체 목록", null, null, Symbol: "\uE946"));
            else
                foreach (var c in containers)
                    items.Add(MakeContainerItem(c));

            items.Add(new LauncherItem("docker images",  "로컬 이미지 목록",    null, ("sub", "images"),  Symbol: "\uE756"));
            items.Add(new LauncherItem("docker all",     "모든 컨테이너 목록",  null, ("sub", "all"),     Symbol: "\uE756"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

        switch (sub)
        {
            case "all":
            case "ps":
            {
                var all = sub == "all";
                var containers = GetContainers(running: !all);
                items.Add(new LauncherItem(
                    $"{(all ? "전체" : "실행 중")} 컨테이너  {containers.Count}개",
                    "", null, null, Symbol: "\uE756"));
                foreach (var c in containers)
                    items.Add(MakeContainerItem(c));
                if (containers.Count == 0)
                    items.Add(new LauncherItem("컨테이너 없음", "", null, null, Symbol: "\uE946"));
                break;
            }

            case "images":
            case "image":
            case "img":
            {
                var images = GetImages();
                items.Add(new LauncherItem($"로컬 이미지  {images.Count}개", "", null, null, Symbol: "\uE756"));
                foreach (var img in images)
                    items.Add(MakeImageItem(img));
                if (images.Count == 0)
                    items.Add(new LauncherItem("이미지 없음", "docker pull <이름> 으로 받기", null, null, Symbol: "\uE946"));
                break;
            }

            case "stop":
            {
                var name = parts.Length > 1 ? parts[1] : "";
                if (string.IsNullOrWhiteSpace(name))
                {
                    // 실행 중 컨테이너 목록 표시 → 클릭 시 stop
                    var running = GetContainers(running: true);
                    items.Add(new LauncherItem("중지할 컨테이너 선택", "Enter → 중지", null, null, Symbol: "\uE756"));
                    foreach (var c in running)
                        items.Add(new LauncherItem($"중지: {c.Name}", c.Image,
                            null, ("stop", c.Id), Symbol: "\uE756"));
                }
                else
                {
                    items.Add(new LauncherItem($"컨테이너 중지: {name}",
                        $"docker stop {name}  · Enter 실행",
                        null, ("stop", name), Symbol: "\uE756"));
                }
                break;
            }

            case "start":
            {
                var name = parts.Length > 1 ? parts[1] : "";
                if (string.IsNullOrWhiteSpace(name))
                {
                    var stopped = GetContainers(running: false, stopped: true);
                    items.Add(new LauncherItem("시작할 컨테이너 선택", "Enter → 시작", null, null, Symbol: "\uE756"));
                    foreach (var c in stopped)
                        items.Add(new LauncherItem($"시작: {c.Name}", c.Image,
                            null, ("start", c.Id), Symbol: "\uE756"));
                }
                else
                {
                    items.Add(new LauncherItem($"컨테이너 시작: {name}",
                        $"docker start {name}  · Enter 실행",
                        null, ("start", name), Symbol: "\uE756"));
                }
                break;
            }

            case "logs":
            case "log":
            {
                var name = parts.Length > 1 ? parts[1] : "";
                if (string.IsNullOrWhiteSpace(name))
                {
                    var running = GetContainers(running: true);
                    foreach (var c in running)
                        items.Add(new LauncherItem($"로그: {c.Name}", "Enter → 터미널에서 로그 보기",
                            null, ("logs", c.Name), Symbol: "\uE756"));
                }
                else
                {
                    items.Add(new LauncherItem($"로그: {name}", $"docker logs -f {name}",
                        null, ("logs", name), Symbol: "\uE756"));
                }
                break;
            }

            case "shell":
            case "exec":
            case "sh":
            {
                var name = parts.Length > 1 ? parts[1] : "";
                if (string.IsNullOrWhiteSpace(name))
                {
                    var running = GetContainers(running: true);
                    foreach (var c in running)
                        items.Add(new LauncherItem($"쉘: {c.Name}", "Enter → 컨테이너 shell 접속",
                            null, ("shell", c.Name), Symbol: "\uE756"));
                }
                else
                {
                    items.Add(new LauncherItem($"쉘 접속: {name}", $"docker exec -it {name} sh",
                        null, ("shell", name), Symbol: "\uE756"));
                }
                break;
            }

            default:
            {
                // 컨테이너 이름 검색
                var all = GetContainers(running: false, stopped: true, all: true);
                var found = all.Where(c =>
                    c.Name.Contains(q, StringComparison.OrdinalIgnoreCase) ||
                    c.Image.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();

                if (found.Count > 0)
                    foreach (var c in found)
                        items.Add(MakeContainerItem(c));
                else
                    items.Add(new LauncherItem($"'{q}' 컨테이너 없음",
                        "docker all → 전체 목록", null, null, Symbol: "\uE946"));
                break;
            }
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data)
        {
            case ("stop", string id):
                RunDockerSilent($"stop {id}");
                NotificationService.Notify("Docker", $"중지: {id}");
                break;

            case ("start", string id):
                RunDockerSilent($"start {id}");
                NotificationService.Notify("Docker", $"시작: {id}");
                break;

            case ("logs", string name):
                RunInTerminal($"docker logs -f {name}");
                break;

            case ("shell", string name):
                RunInTerminal($"docker exec -it {name} sh");
                break;

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

            case ("open_url", string url):
                try
                {
                    System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
                    { FileName = url, UseShellExecute = true });
                }
                catch { /* 비핵심 */ }
                break;
        }
        return Task.CompletedTask;
    }

    // ── Docker 조회 ──────────────────────────────────────────────────────────

    private record DockerContainer(string Id, string Name, string Image, string Status, string Ports);
    private record DockerImage(string Repository, string Tag, string Id, string Size, string Created);

    private static List<DockerContainer> GetContainers(bool running = true, bool stopped = false, bool all = false)
    {
        var result = new List<DockerContainer>();
        try
        {
            var filter = all || (!running && stopped) ? "-a" : (running ? "" : "--filter status=exited");
            var output = RunDockerOutput($"ps {filter} --format \"{{{{.ID}}}}\\t{{{{.Names}}}}\\t{{{{.Image}}}}\\t{{{{.Status}}}}\\t{{{{.Ports}}}}\"");
            foreach (var line in output.Split('\n'))
            {
                var trimmed = line.Trim();
                if (string.IsNullOrWhiteSpace(trimmed)) continue;
                var cols = trimmed.Split('\t');
                if (cols.Length < 4) continue;
                result.Add(new DockerContainer(
                    Id:     cols[0],
                    Name:   cols[1],
                    Image:  cols[2],
                    Status: cols[3],
                    Ports:  cols.Length > 4 ? cols[4] : ""));
            }
        }
        catch { /* Docker 없음 */ }
        return result;
    }

    private static List<DockerImage> GetImages()
    {
        var result = new List<DockerImage>();
        try
        {
            var output = RunDockerOutput("images --format \"{{.Repository}}\\t{{.Tag}}\\t{{.ID}}\\t{{.Size}}\\t{{.CreatedSince}}\"");
            foreach (var line in output.Split('\n'))
            {
                var trimmed = line.Trim();
                if (string.IsNullOrWhiteSpace(trimmed)) continue;
                var cols = trimmed.Split('\t');
                if (cols.Length < 4) continue;
                result.Add(new DockerImage(
                    Repository: cols[0],
                    Tag:        cols.Length > 1 ? cols[1] : "latest",
                    Id:         cols.Length > 2 ? cols[2] : "",
                    Size:       cols.Length > 3 ? cols[3] : "",
                    Created:    cols.Length > 4 ? cols[4] : ""));
            }
        }
        catch { /* Docker 없음 */ }
        return result;
    }

    private static string RunDockerOutput(string args)
    {
        var psi = new System.Diagnostics.ProcessStartInfo
        {
            FileName               = "docker",
            Arguments              = args,
            UseShellExecute        = false,
            RedirectStandardOutput = true,
            CreateNoWindow         = true,
            StandardOutputEncoding = Encoding.UTF8,
        };
        using var proc = System.Diagnostics.Process.Start(psi);
        if (proc == null) return "";
        var output = proc.StandardOutput.ReadToEnd();
        proc.WaitForExit(5000);
        return output;
    }

    private static void RunDockerSilent(string args)
    {
        try
        {
            var psi = new System.Diagnostics.ProcessStartInfo
            {
                FileName = "docker", Arguments = args,
                UseShellExecute = false, CreateNoWindow = true,
            };
            using var proc = System.Diagnostics.Process.Start(psi);
            proc?.WaitForExit(10000);
        }
        catch { /* 비핵심 */ }
    }

    private static bool IsDockerAvailable()
    {
        try
        {
            var psi = new System.Diagnostics.ProcessStartInfo
            {
                FileName = "docker", Arguments = "version --format json",
                UseShellExecute = false, CreateNoWindow = true,
                RedirectStandardOutput = true,
            };
            using var proc = System.Diagnostics.Process.Start(psi);
            proc?.WaitForExit(3000);
            return proc?.ExitCode == 0;
        }
        catch { return false; }
    }

    private static LauncherItem MakeContainerItem(DockerContainer c)
    {
        var isRunning = c.Status.StartsWith("Up", StringComparison.OrdinalIgnoreCase);
        var icon = isRunning ? "\uE768" : "\uE71A";
        var ports = string.IsNullOrWhiteSpace(c.Ports) ? "" : $"  ·  {c.Ports}";
        return new LauncherItem(c.Name,
            $"{c.Status}{ports}  ·  {c.Image}",
            null, ("copy", c.Id), Symbol: icon);
    }

    private static LauncherItem MakeImageItem(DockerImage img)
    {
        var name = img.Tag == "<none>" ? img.Repository : $"{img.Repository}:{img.Tag}";
        return new LauncherItem(name, $"{img.Size}  ·  {img.Created}  ·  {img.Id[..Math.Min(12, img.Id.Length)]}",
            null, ("copy", name), Symbol: "\uE756");
    }

    private static void RunInTerminal(string cmd)
    {
        try
        {
            System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
            {
                FileName = "cmd", Arguments = $"/K {cmd}", UseShellExecute = true,
            });
        }
        catch { /* 비핵심 */ }
    }
}
