using System.Diagnostics;
using System.Windows;
using AxCopilot.Models;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// L8-4: SSH 퀵 커넥트 핸들러. "ssh" 프리픽스로 사용합니다.
///
/// 예: ssh                       → 저장된 SSH 호스트 목록
///     ssh dev                   → 이름/호스트에 "dev" 포함된 항목 필터
///     ssh add user@host         → 빠른 호스트 추가 (이름 = host, 포트 22)
///     ssh add name user@host:22 → 이름 지정하여 추가
///     ssh del <이름>             → 호스트 삭제
/// Enter → Windows Terminal(ssh) 또는 PuTTY로 연결.
/// 사내 모드에서도 항상 사용 가능 (SSH는 내부 서버 접속이 주 용도).
/// </summary>
public class SshHandler : IActionHandler
{
    private readonly SettingsService _settings;

    public SshHandler(SettingsService settings) { _settings = settings; }

    public string? Prefix => "ssh";

    public PluginMetadata Metadata => new(
        "SSH",
        "SSH 퀵 커넥트 — 호스트 저장 · 빠른 연결",
        "1.0",
        "AX");

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

        if (string.IsNullOrWhiteSpace(q))
        {
            if (hosts.Count == 0)
            {
                items.Add(new LauncherItem(
                    "SSH 호스트 없음",
                    "ssh add user@host  또는  ssh add 이름 user@host:22",
                    null, null, Symbol: "\uE968"));
            }
            else
            {
                foreach (var h in hosts)
                    items.Add(MakeHostItem(h));
            }
            items.Add(new LauncherItem(
                "ssh add user@host",
                "새 호스트 추가",
                null, null, Symbol: "\uE710"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

        // ── add ─────────────────────────────────────────────────────────
        if (sub == "add")
        {
            SshHostEntry? entry = null;

            if (parts.Length == 2)
            {
                // ssh add user@host[:port]
                entry = ParseUserHost(parts[1]);
                if (entry != null) entry.Name = entry.Host;
            }
            else if (parts.Length == 3)
            {
                // ssh add <name> user@host[:port]
                entry = ParseUserHost(parts[2]);
                if (entry != null) entry.Name = parts[1];
            }

            if (entry != null)
            {
                items.Add(new LauncherItem(
                    $"추가: {entry.Name}",
                    $"{entry.User}@{entry.Host}:{entry.Port}",
                    null,
                    ("add", entry),
                    Symbol: "\uE710"));
            }
            else
            {
                items.Add(new LauncherItem(
                    "형식: ssh add user@host[:port]",
                    "또는: ssh add 이름 user@host:22",
                    null, null, Symbol: "\uE783"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // ── del ─────────────────────────────────────────────────────────
        if (sub == "del" || sub == "delete" || sub == "rm")
        {
            var nameQuery = parts.Length >= 2 ? parts[1].ToLowerInvariant() : "";
            var toDelete  = hosts
                .Where(h => h.Name.Contains(nameQuery, StringComparison.OrdinalIgnoreCase)
                         || h.Host.Contains(nameQuery, StringComparison.OrdinalIgnoreCase))
                .ToList();

            if (toDelete.Count == 0)
            {
                items.Add(new LauncherItem("삭제 대상 없음", nameQuery, null, null, Symbol: "\uE783"));
            }
            else
            {
                foreach (var h in toDelete)
                    items.Add(new LauncherItem(
                        $"삭제: {h.Name}",
                        $"{h.User}@{h.Host}:{h.Port}",
                        null,
                        ("del", h.Id),
                        Symbol: "\uE74D"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // ── 검색 (이름 / 호스트 / 사용자 / 메모) ─────────────────────────
        var filtered = hosts.Where(h =>
            h.Name.Contains(q, StringComparison.OrdinalIgnoreCase)
            || h.Host.Contains(q, StringComparison.OrdinalIgnoreCase)
            || h.User.Contains(q, StringComparison.OrdinalIgnoreCase)
            || h.Note.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();

        if (filtered.Count > 0)
        {
            foreach (var h in filtered)
                items.Add(MakeHostItem(h));
        }
        else
        {
            // 직접 접속 시도 (user@host 형식)
            var entry = ParseUserHost(q);
            if (entry != null)
            {
                items.Add(new LauncherItem(
                    $"연결: {entry.User}@{entry.Host}:{entry.Port}",
                    "Enter → Windows Terminal로 연결",
                    null,
                    ("connect", entry),
                    Symbol: "\uE968"));
                items.Add(new LauncherItem(
                    $"저장 후 연결",
                    $"이름: {entry.Host}",
                    null,
                    ("add_connect", entry),
                    Symbol: "\uE710"));
            }
            else
            {
                items.Add(new LauncherItem("호스트를 찾을 수 없음", q, null, null, Symbol: "\uE783"));
            }
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data)
        {
            case ("connect", SshHostEntry h):
                ConnectSsh(h);
                break;

            case ("add", SshHostEntry h):
                _settings.Settings.SshHosts.RemoveAll(e =>
                    e.Host.Equals(h.Host, StringComparison.OrdinalIgnoreCase)
                    && e.User.Equals(h.User, StringComparison.OrdinalIgnoreCase)
                    && e.Port == h.Port);
                _settings.Settings.SshHosts.Add(h);
                _settings.Save();
                NotificationService.Notify("SSH", $"'{h.Name}' 호스트를 저장했습니다.");
                break;

            case ("add_connect", SshHostEntry h):
                if (string.IsNullOrEmpty(h.Name)) h.Name = h.Host;
                _settings.Settings.SshHosts.Add(h);
                _settings.Save();
                ConnectSsh(h);
                break;

            case ("del", string id):
                var removed = _settings.Settings.SshHosts
                    .RemoveAll(e => e.Id == id);
                if (removed > 0)
                {
                    _settings.Save();
                    NotificationService.Notify("SSH", "호스트를 삭제했습니다.");
                }
                break;

            // 호스트 항목 직접 Enter
            case SshHostEntry host:
                ConnectSsh(host);
                break;
        }
        return Task.CompletedTask;
    }

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

    private static LauncherItem MakeHostItem(SshHostEntry h)
    {
        var portStr = h.Port != 22 ? $":{h.Port}" : "";
        return new LauncherItem(
            h.Name,
            $"{h.User}@{h.Host}{portStr}{(string.IsNullOrEmpty(h.Note) ? "" : "  ·  " + h.Note)}",
            null,
            h,
            Symbol: "\uE968");
    }

    /// <summary>Windows Terminal 또는 PuTTY로 SSH 연결을 시작합니다.</summary>
    private static void ConnectSsh(SshHostEntry h)
    {
        try
        {
            // Windows Terminal (wt.exe) 우선
            var wtPath = FindExecutable("wt.exe");
            if (!string.IsNullOrEmpty(wtPath))
            {
                var portArgs = h.Port != 22 ? $" -p {h.Port}" : "";
                var userHost = string.IsNullOrEmpty(h.User)
                    ? h.Host : $"{h.User}@{h.Host}";
                Process.Start(new ProcessStartInfo
                {
                    FileName        = wtPath,
                    Arguments       = $"ssh {userHost}{portArgs}",
                    UseShellExecute = true,
                });
                return;
            }

            // PuTTY 대체
            var puttyPath = FindExecutable("putty.exe");
            if (!string.IsNullOrEmpty(puttyPath))
            {
                var userHost = string.IsNullOrEmpty(h.User)
                    ? h.Host : $"{h.User}@{h.Host}";
                Process.Start(new ProcessStartInfo
                {
                    FileName        = puttyPath,
                    Arguments       = $"-ssh {userHost} -P {h.Port}",
                    UseShellExecute = true,
                });
                return;
            }

            // PowerShell 폴백
            var portArgs2 = h.Port != 22 ? $" -p {h.Port}" : "";
            var cmd       = string.IsNullOrEmpty(h.User)
                ? $"ssh {h.Host}{portArgs2}"
                : $"ssh {h.User}@{h.Host}{portArgs2}";

            Process.Start(new ProcessStartInfo
            {
                FileName        = "powershell.exe",
                Arguments       = $"-NoExit -Command \"{cmd}\"",
                UseShellExecute = true,
            });
        }
        catch (Exception ex)
        {
            NotificationService.Notify("SSH 오류", ex.Message);
        }
    }

    /// <summary>PATH 및 일반 설치 경로에서 실행 파일을 찾습니다.</summary>
    private static string? FindExecutable(string exe)
    {
        // PATH 검색
        var envPath = Environment.GetEnvironmentVariable("PATH") ?? "";
        foreach (var dir in envPath.Split(';', StringSplitOptions.RemoveEmptyEntries))
        {
            var full = System.IO.Path.Combine(dir.Trim(), exe);
            if (System.IO.File.Exists(full)) return full;
        }

        // 일반 설치 경로
        var candidates = new[]
        {
            System.IO.Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                "Microsoft\\WindowsApps", exe),
            System.IO.Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), exe),
            System.IO.Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), exe),
        };

        return candidates.FirstOrDefault(System.IO.File.Exists);
    }

    /// <summary>user@host:port 형식을 파싱합니다.</summary>
    private static SshHostEntry? ParseUserHost(string s)
    {
        if (string.IsNullOrEmpty(s)) return null;

        string user = "";
        string host = s;
        int    port = 22;

        // user@host 파싱
        var atIdx = s.IndexOf('@');
        if (atIdx >= 0)
        {
            user = s[..atIdx];
            host = s[(atIdx + 1)..];
        }

        // host:port 파싱
        var colonIdx = host.LastIndexOf(':');
        if (colonIdx >= 0 && int.TryParse(host[(colonIdx + 1)..], out var p))
        {
            port = p;
            host = host[..colonIdx];
        }

        if (string.IsNullOrEmpty(host)) return null;

        return new SshHostEntry
        {
            Id   = Guid.NewGuid().ToString(),
            Name = host,
            Host = host,
            Port = port,
            User = user,
        };
    }
}
