using System.Diagnostics;
using System.IO;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// Phase L3-5: 파일 태그 핸들러. "tag" 프리픽스로 사용합니다.
/// 파일·폴더에 사용자 태그를 부여하고 태그 기반으로 검색합니다.
///
/// 사용법:
///   tag              → 전체 태그 목록 (태그명 + 파일 수)
///   tag work         → "work" 태그가 부여된 파일 목록
///   tag add work C:\path\file.docx → 파일에 "work" 태그 추가
///   tag del work C:\path\file.docx → 파일에서 "work" 태그 제거
///   tag clear C:\path\file.docx   → 파일의 모든 태그 제거
/// </summary>
public class TagHandler : IActionHandler
{
    public string? Prefix => "tag";

    public PluginMetadata Metadata => new(
        "FileTag",
        "파일 태그 — tag",
        "1.0",
        "AX",
        "파일·폴더에 사용자 태그를 부여하고 태그 기반으로 검색합니다.");

    private static FileTagService Tags => FileTagService.Instance;

    // ─── GetItemsAsync ───────────────────────────────────────────────────────

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

        // ── add 명령: tag add <태그> <경로> ────────────────────────────────
        if (q.StartsWith("add ", StringComparison.OrdinalIgnoreCase))
        {
            var rest = q[4..].Trim();
            var spaceIdx = rest.IndexOf(' ');
            if (spaceIdx > 0)
            {
                var tag  = rest[..spaceIdx].Trim();
                var path = rest[(spaceIdx + 1)..].Trim();
                return Task.FromResult<IEnumerable<LauncherItem>>(
                [
                    new LauncherItem(
                        $"태그 추가: [{tag}] → {Path.GetFileName(path)}",
                        $"{path}  ·  Enter로 추가",
                        null,
                        ValueTuple.Create("__TAG_ADD__", tag, path),
                        Symbol: Symbols.Tag)
                ]);
            }
            return HelpItems("tag add [태그] [경로]", "예: tag add work C:\\project\\report.docx");
        }

        // ── del 명령: tag del <태그> <경로> ────────────────────────────────
        if (q.StartsWith("del ", StringComparison.OrdinalIgnoreCase))
        {
            var rest = q[4..].Trim();
            var spaceIdx = rest.IndexOf(' ');
            if (spaceIdx > 0)
            {
                var tag  = rest[..spaceIdx].Trim();
                var path = rest[(spaceIdx + 1)..].Trim();
                return Task.FromResult<IEnumerable<LauncherItem>>(
                [
                    new LauncherItem(
                        $"태그 제거: [{tag}] ← {Path.GetFileName(path)}",
                        $"{path}  ·  Enter로 제거",
                        null,
                        ValueTuple.Create("__TAG_DEL__", tag, path),
                        Symbol: Symbols.Delete)
                ]);
            }
            return HelpItems("tag del [태그] [경로]", "예: tag del work C:\\project\\report.docx");
        }

        // ── clear 명령: tag clear <경로> ───────────────────────────────────
        if (q.StartsWith("clear ", StringComparison.OrdinalIgnoreCase))
        {
            var path = q[6..].Trim();
            if (!string.IsNullOrEmpty(path))
            {
                var currentTags = Tags.GetTags(path);
                var tagList = currentTags.Count > 0
                    ? string.Join(", ", currentTags.Select(t => $"[{t}]"))
                    : "태그 없음";
                return Task.FromResult<IEnumerable<LauncherItem>>(
                [
                    new LauncherItem(
                        $"태그 전체 제거: {Path.GetFileName(path)}",
                        $"{tagList}  ·  Enter로 모두 삭제",
                        null,
                        ValueTuple.Create("__TAG_CLEAR__", path),
                        Symbol: Symbols.Delete)
                ]);
            }
            return HelpItems("tag clear [경로]", "예: tag clear C:\\project\\report.docx");
        }

        // ── 태그 검색 또는 전체 목록 ─────────────────────────────────────────
        return string.IsNullOrEmpty(q)
            ? BuildTagListItems()
            : BuildTagSearchItems(q);
    }

    // ─── ExecuteAsync ────────────────────────────────────────────────────────

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        // 태그 추가
        if (item.Data is ValueTuple<string, string, string> addCmd &&
            addCmd.Item1 == "__TAG_ADD__")
        {
            Tags.AddTag(addCmd.Item3, addCmd.Item2);
            NotificationService.Notify("AX Copilot",
                $"태그 추가: [{addCmd.Item2}] → {Path.GetFileName(addCmd.Item3)}");
            return Task.CompletedTask;
        }

        // 태그 제거
        if (item.Data is ValueTuple<string, string, string> delCmd &&
            delCmd.Item1 == "__TAG_DEL__")
        {
            Tags.RemoveTag(delCmd.Item3, delCmd.Item2);
            NotificationService.Notify("AX Copilot",
                $"태그 제거: [{delCmd.Item2}] ← {Path.GetFileName(delCmd.Item3)}");
            return Task.CompletedTask;
        }

        // 전체 태그 제거
        if (item.Data is ValueTuple<string, string> clearCmd &&
            clearCmd.Item1 == "__TAG_CLEAR__")
        {
            Tags.ClearTags(clearCmd.Item2);
            NotificationService.Notify("AX Copilot",
                $"태그 전체 제거: {Path.GetFileName(clearCmd.Item2)}");
            return Task.CompletedTask;
        }

        // 파일/폴더 열기
        if (item.Data is string filePath)
        {
            try
            {
                Process.Start(new ProcessStartInfo(filePath) { UseShellExecute = true });
            }
            catch (Exception ex)
            {
                LogService.Warn($"[TagHandler] 파일 열기 실패: {ex.Message}");
            }
        }

        return Task.CompletedTask;
    }

    // ─── 내부 헬퍼 ──────────────────────────────────────────────────────────

    private static Task<IEnumerable<LauncherItem>> BuildTagListItems()
    {
        var allTags = Tags.GetAllTags();
        if (allTags.Count == 0)
        {
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem(
                    "등록된 태그가 없습니다",
                    "tag add [태그] [경로]로 태그를 추가하세요",
                    null, null, Symbol: Symbols.Info),
                new LauncherItem(
                    "사용법 보기",
                    "tag add work C:\\path\\file.docx  /  tag work  /  tag clear C:\\path",
                    null, null, Symbol: Symbols.Info),
            ]);
        }

        var items = allTags
            .OrderByDescending(kv => kv.Value)
            .ThenBy(kv => kv.Key)
            .Take(12)
            .Select(kv => new LauncherItem(
                $"[{kv.Key}]",
                $"{kv.Value}개 파일  ·  tag {kv.Key}로 파일 목록 보기",
                null, null,
                Symbol: Symbols.Tag))
            .ToList<LauncherItem>();

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

    private static Task<IEnumerable<LauncherItem>> BuildTagSearchItems(string q)
    {
        var allTags = Tags.GetAllTags();

        // 입력 q와 prefix match되는 태그 먼저, 그 다음 contains 순
        var matchedTags = allTags.Keys
            .Where(t => t.Contains(q, StringComparison.OrdinalIgnoreCase))
            .OrderBy(t => t.StartsWith(q, StringComparison.OrdinalIgnoreCase) ? 0 : 1)
            .ThenBy(t => t)
            .ToList();

        if (!matchedTags.Any())
        {
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem(
                    $"[{q}] 태그에 해당하는 파일 없음",
                    "tag add [태그] [경로]로 태그를 추가하세요",
                    null, null, Symbol: Symbols.Info)
            ]);
        }

        var items = new List<LauncherItem>();
        var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

        foreach (var tag in matchedTags.Take(2))
        {
            var files = Tags.GetFilesByTag(tag);
            foreach (var path in files.Take(6))
            {
                if (!seen.Add(path)) continue;

                var isDir  = Directory.Exists(path);
                var isFile = File.Exists(path);
                var symbol = isDir ? Symbols.Folder
                           : isFile ? Symbols.File
                           : Symbols.Warning;
                var hint = isDir  ? "폴더 열기"
                         : isFile ? "파일 열기"
                         : "경로를 찾을 수 없음";

                items.Add(new LauncherItem(
                    Path.GetFileName(path),
                    $"[{tag}]  ·  {path}  ·  {hint}",
                    null, path,
                    Symbol: symbol));
            }
        }

        if (!items.Any())
        {
            items.Add(new LauncherItem(
                $"[{q}] 태그 파일 접근 불가",
                "파일이 삭제되었거나 경로가 변경되었을 수 있습니다",
                null, null, Symbol: Symbols.Warning));
        }

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

    private static Task<IEnumerable<LauncherItem>> HelpItems(string usage, string example) =>
        Task.FromResult<IEnumerable<LauncherItem>>(
        [
            new LauncherItem(
                $"사용법: {usage}",
                example,
                null, null, Symbol: Symbols.Info)
        ]);
}
