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

namespace AxCopilot.Handlers;

/// <summary>
/// L4-1: 인라인 파일 탐색기 핸들러.
/// 입력이 파일시스템 경로처럼 보이면 (예: C:\, D:\Users\) 해당 폴더의 내용을 런처 목록으로 표시합니다.
/// → 키로 하위 폴더 진입, ← 키 또는 Backspace로 상위 폴더 이동.
/// prefix=null: 일반 쿼리 파이프라인에서 경로 감지 후 동작.
/// </summary>
public class FileBrowserHandler : IActionHandler
{
    public string? Prefix => null; // 경로 패턴 직접 감지

    public PluginMetadata Metadata => new(
        "FileBrowser",
        "파일 탐색기 — 경로 입력 후 → 키로 탐색",
        "1.0",
        "AX");

    // C:\, D:\path, \\server\share, ~\ 패턴 감지
    private static readonly Regex PathPattern = new(
        @"^([A-Za-z]:\\|\\\\|~\\|~\/|\/)",
        RegexOptions.Compiled);

    /// <summary>쿼리가 파일시스템 경로처럼 보이는지 빠르게 판별합니다.</summary>
    public static bool IsPathQuery(string query)
        => !string.IsNullOrEmpty(query) && PathPattern.IsMatch(query.Trim());

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

        // 경로가 아닌 쿼리는 빈 결과 반환 (다른 핸들러가 처리)
        if (!IsPathQuery(query.Trim()))
            return Task.FromResult<IEnumerable<LauncherItem>>(Array.Empty<LauncherItem>());

        // 입력이 존재하는 디렉터리이면 그 내용 표시
        if (Directory.Exists(q))
            return Task.FromResult(ListDirectory(q));

        // 부분 경로: 마지막 세그먼트를 필터로 사용
        var parent = Path.GetDirectoryName(q);
        var filter = Path.GetFileName(q).ToLowerInvariant();

        if (parent != null && Directory.Exists(parent))
            return Task.FromResult(ListDirectory(parent, filter));

        return Task.FromResult<IEnumerable<LauncherItem>>(new[]
        {
            new LauncherItem("경로를 찾을 수 없습니다", q, null, null, Symbol: Symbols.Error)
        });
    }

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is FileBrowserEntry { IsFolder: true } dir)
        {
            // 폴더: 탐색기로 열기
            System.Diagnostics.Process.Start(
                new System.Diagnostics.ProcessStartInfo("explorer.exe", dir.Path)
                { UseShellExecute = true });
        }
        else if (item.Data is FileBrowserEntry { IsFolder: false } file)
        {
            // 파일: 기본 앱으로 열기
            System.Diagnostics.Process.Start(
                new System.Diagnostics.ProcessStartInfo(file.Path)
                { UseShellExecute = true });
        }
        return Task.CompletedTask;
    }

    // ─── 디렉터리 내용 나열 ─────────────────────────────────────────────────────

    private static IEnumerable<LauncherItem> ListDirectory(string dir, string filter = "")
    {
        var items = new List<LauncherItem>();

        // 상위 폴더 항목 (루트가 아닐 때)
        var parent = Path.GetDirectoryName(dir.TrimEnd('\\', '/'));
        if (!string.IsNullOrEmpty(parent))
        {
            items.Add(new LauncherItem(
                ".. (상위 폴더)",
                parent,
                IconCacheService.GetIconPath(parent, true),
                new FileBrowserEntry(parent, true),
                Symbol: "\uE74A")); // Back 아이콘
        }

        try
        {
            // 폴더 먼저
            var dirs = Directory.GetDirectories(dir)
                .Where(d => string.IsNullOrEmpty(filter) ||
                            Path.GetFileName(d).Contains(filter, StringComparison.OrdinalIgnoreCase))
                .OrderBy(d => Path.GetFileName(d), StringComparer.OrdinalIgnoreCase)
                .Take(40);

            foreach (var d in dirs)
            {
                var name = Path.GetFileName(d);
                items.Add(new LauncherItem(
                    name,
                    d,
                    IconCacheService.GetIconPath(d, true),
                    new FileBrowserEntry(d, true),
                    Symbol: Symbols.Folder));
            }

            // 파일
            var files = Directory.GetFiles(dir)
                .Where(f => string.IsNullOrEmpty(filter) ||
                            Path.GetFileName(f).Contains(filter, StringComparison.OrdinalIgnoreCase))
                .OrderBy(f => Path.GetFileName(f), StringComparer.OrdinalIgnoreCase)
                .Take(30);

            foreach (var f in files)
            {
                var name = Path.GetFileName(f);
                var ext  = Path.GetExtension(f).ToLowerInvariant();
                var size = FormatSize(new FileInfo(f).Length);
                items.Add(new LauncherItem(
                    name,
                    $"{size}  ·  {ext.TrimStart('.')} 파일",
                    IconCacheService.GetIconPath(f),
                    new FileBrowserEntry(f, false),
                    Symbol: ExtToSymbol(ext)));
            }
        }
        catch (UnauthorizedAccessException)
        {
            items.Add(new LauncherItem("접근 권한 없음", dir, null, null, Symbol: Symbols.Error));
        }
        catch (Exception ex)
        {
            items.Add(new LauncherItem("읽기 오류", ex.Message, null, null, Symbol: Symbols.Error));
        }

        if (items.Count == 0 || (items.Count == 1 && items[0].Symbol == "\uE74A"))
            items.Add(new LauncherItem("(빈 폴더)", dir, null, null, Symbol: Symbols.Folder));

        return items;
    }

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

    private static string ExpandPath(string path)
    {
        if (path.StartsWith("~")) path = "%USERPROFILE%" + path[1..];
        return Environment.ExpandEnvironmentVariables(path);
    }

    private static string FormatSize(long bytes) => bytes switch
    {
        < 1_024L              => $"{bytes} B",
        < 1_024L * 1_024      => $"{bytes / 1_024.0:F1} KB",
        < 1_024L * 1_024 * 1_024 => $"{bytes / 1_048_576.0:F1} MB",
        _                     => $"{bytes / 1_073_741_824.0:F1} GB",
    };

    private static string ExtToSymbol(string ext) => ext switch
    {
        ".exe" or ".msi"             => Symbols.App,
        ".pdf"                       => "\uEA90",
        ".docx" or ".doc"            => "\uE8A5",
        ".xlsx" or ".xls"            => "\uE9F9",
        ".pptx" or ".ppt"            => "\uE8A5",
        ".zip" or ".7z" or ".rar"    => "\uED25",
        ".mp4" or ".avi" or ".mkv"   => "\uE714",
        ".mp3" or ".wav" or ".flac"  => "\uE767",
        ".png" or ".jpg" or ".jpeg" or ".gif" => "\uEB9F",
        ".txt" or ".md" or ".log"    => "\uE8A5",
        ".cs" or ".py" or ".js" or ".ts" => "\uE8A5",
        ".lnk"                       => "\uE71B",
        _                            => "\uE7C3",
    };
}

/// <summary>파일 탐색기 핸들러에서 사용하는 항목 데이터</summary>
public record FileBrowserEntry(string Path, bool IsFolder);
