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

namespace AxCopilot.Handlers;

/// <summary>
/// L9-3: 시스템 정리 핸들러. "clean" 프리픽스로 사용합니다.
///
/// 예: clean                → 정리 가능한 항목 목록 + 예상 용량
///     clean temp           → Windows 임시 파일 정리 (%TEMP%)
///     clean recycle        → 휴지통 비우기
///     clean downloads      → 다운로드 폴더 오래된 파일 목록 (30일 이상)
///     clean logs           → 앱 로그 폴더 정리 (%APPDATA%\AxCopilot\logs)
///     clean all            → temp + recycle + logs 한 번에 정리
/// </summary>
public class CleanHandler : IActionHandler
{
    public string? Prefix => "clean";

    public PluginMetadata Metadata => new(
        "Clean",
        "시스템 정리 — 임시 파일 · 휴지통 · 다운로드 · 로그",
        "1.0",
        "AX");

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

        if (string.IsNullOrWhiteSpace(q))
        {
            // 각 영역 크기 미리보기
            var tempSize      = GetDirSize(Path.GetTempPath());
            var recycleSize   = GetRecycleBinSize();
            var downloadsSize = GetOldDownloadsSize(30);
            var logSize       = GetDirSize(GetAppLogPath());

            var total = tempSize + recycleSize + downloadsSize + logSize;

            items.Add(new LauncherItem(
                $"정리 가능  {FormatBytes(total)}",
                "항목을 선택하거나 clean all 로 모두 정리",
                null, null, Symbol: "\uE74D"));

            items.Add(MakeCleanItem("temp",      "\uE8B6", "임시 파일 (%TEMP%)",    tempSize));
            items.Add(MakeCleanItem("recycle",   "\uE74D", "휴지통",                 recycleSize));
            items.Add(MakeCleanItem("downloads", "\uE896", "다운로드 (30일 이상)",   downloadsSize));
            items.Add(MakeCleanItem("logs",      "\uE9D9", "AxCopilot 로그 파일",    logSize));
            items.Add(new LauncherItem(
                "clean all",
                $"temp + recycle + logs 한 번에 정리  ({FormatBytes(tempSize + recycleSize + logSize)})",
                null,
                ("clean_all", ""),
                Symbol: "\uE74D"));

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

        switch (q)
        {
            case "temp":
            {
                var tempPath = Path.GetTempPath();
                var size     = GetDirSize(tempPath);
                var count    = SafeCountFiles(tempPath);
                items.Add(new LauncherItem(
                    $"임시 파일 정리  {FormatBytes(size)}",
                    $"{count}개 파일  ·  {tempPath}",
                    null,
                    ("clean_temp", tempPath),
                    Symbol: "\uE8B6"));
                break;
            }
            case "recycle":
            {
                var size = GetRecycleBinSize();
                items.Add(new LauncherItem(
                    $"휴지통 비우기  {FormatBytes(size)}",
                    "복구 불가능합니다. Enter로 실행",
                    null,
                    ("clean_recycle", ""),
                    Symbol: "\uE74D"));
                break;
            }
            case "downloads":
            {
                var downloadsPath = Environment.GetFolderPath(
                    Environment.SpecialFolder.UserProfile);
                downloadsPath = Path.Combine(downloadsPath, "Downloads");
                var oldFiles = GetOldFiles(downloadsPath, 30);
                var totalSz  = oldFiles.Sum(f => f.Length);

                items.Add(new LauncherItem(
                    $"다운로드 30일 이상 파일  {FormatBytes(totalSz)}",
                    $"{oldFiles.Count}개 파일",
                    null,
                    ("list_downloads", downloadsPath),
                    Symbol: "\uE896"));

                foreach (var f in oldFiles.Take(15))
                {
                    items.Add(new LauncherItem(
                        f.Name,
                        $"{FormatBytes(f.Length)}  ·  {f.LastWriteTime:MM-dd HH:mm}",
                        null,
                        ("open_file", f.FullName),
                        Symbol: "\uE8A5"));
                }
                break;
            }
            case "logs":
            {
                var logPath = GetAppLogPath();
                var size    = GetDirSize(logPath);
                var count   = SafeCountFiles(logPath);
                items.Add(new LauncherItem(
                    $"AxCopilot 로그 정리  {FormatBytes(size)}",
                    $"{count}개 파일  ·  {logPath}",
                    null,
                    ("clean_logs", logPath),
                    Symbol: "\uE9D9"));
                break;
            }
            case "all":
            {
                var tempSz    = GetDirSize(Path.GetTempPath());
                var recycleSz = GetRecycleBinSize();
                var logSz     = GetDirSize(GetAppLogPath());
                items.Add(new LauncherItem(
                    $"모두 정리  {FormatBytes(tempSz + recycleSz + logSz)}",
                    "temp + recycle + logs  ·  Enter로 실행",
                    null,
                    ("clean_all", ""),
                    Symbol: "\uE74D"));
                break;
            }
            default:
                items.Add(new LauncherItem("서브커맨드", "temp · recycle · downloads · logs · all", null, null, Symbol: "\uE946"));
                break;
        }

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

    public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data)
        {
            case ("clean_temp", string path):
                await Task.Run(() =>
                {
                    var deleted = CleanDirectory(path, recursive: false);
                    NotificationService.Notify("정리 완료", $"임시 파일 {deleted}개 삭제");
                }, ct);
                break;

            case ("clean_recycle", _):
                await Task.Run(() =>
                {
                    EmptyRecycleBin();
                    NotificationService.Notify("정리 완료", "휴지통을 비웠습니다.");
                }, ct);
                break;

            case ("clean_logs", string path):
                await Task.Run(() =>
                {
                    var deleted = CleanDirectory(path, recursive: true);
                    NotificationService.Notify("정리 완료", $"로그 파일 {deleted}개 삭제");
                }, ct);
                break;

            case ("clean_all", _):
                await Task.Run(() =>
                {
                    var t1 = CleanDirectory(Path.GetTempPath(), recursive: false);
                    EmptyRecycleBin();
                    var t2 = CleanDirectory(GetAppLogPath(), recursive: true);
                    NotificationService.Notify("모두 정리 완료",
                        $"임시 {t1}개, 로그 {t2}개 삭제, 휴지통 비움");
                }, ct);
                break;

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

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

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

    private static LauncherItem MakeCleanItem(string sub, string icon, string label, long size) =>
        new(
            $"clean {sub}",
            $"{label}  ·  {FormatBytes(size)}",
            null,
            ($"clean_{sub}", ""),
            Symbol: icon);

    private static long GetDirSize(string path)
    {
        if (!Directory.Exists(path)) return 0;
        try
        {
            return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
                            .Sum(f => { try { return new FileInfo(f).Length; } catch { return 0; } });
        }
        catch { return 0; }
    }

    private static long GetRecycleBinSize()
    {
        try
        {
            // SHQueryRecycleBin P/Invoke 대신 Shell32 통해 추정
            // 간단히 0 반환 (실제 크기는 SHQueryRecycleBinW P/Invoke 필요)
            return 0;
        }
        catch { return 0; }
    }

    private static long GetOldDownloadsSize(int olderThanDays)
    {
        try
        {
            var path = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                "Downloads");
            return GetOldFiles(path, olderThanDays).Sum(f => f.Length);
        }
        catch { return 0; }
    }

    private static List<FileInfo> GetOldFiles(string dir, int olderThanDays)
    {
        if (!Directory.Exists(dir)) return [];
        var cutoff = DateTime.Now.AddDays(-olderThanDays);
        try
        {
            return Directory.EnumerateFiles(dir)
                            .Select(f => new FileInfo(f))
                            .Where(fi => fi.LastWriteTime < cutoff)
                            .OrderByDescending(fi => fi.Length)
                            .ToList();
        }
        catch { return []; }
    }

    private static int SafeCountFiles(string path)
    {
        if (!Directory.Exists(path)) return 0;
        try
        {
            return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Count();
        }
        catch { return 0; }
    }

    private static int CleanDirectory(string path, bool recursive)
    {
        if (!Directory.Exists(path)) return 0;
        int deleted = 0;
        var opts    = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
        foreach (var file in Directory.EnumerateFiles(path, "*", opts))
        {
            try { File.Delete(file); deleted++; } catch { /* 잠긴 파일 무시 */ }
        }
        return deleted;
    }

    [System.Runtime.InteropServices.DllImport("shell32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
    private static extern int SHEmptyRecycleBin(IntPtr hwnd, string? pszRootPath, uint dwFlags);

    private static void EmptyRecycleBin()
    {
        try
        {
            // SHERB_NOCONFIRMATION=0x1, SHERB_NOPROGRESSUI=0x2, SHERB_NOSOUND=0x4
            SHEmptyRecycleBin(IntPtr.Zero, null, 0x07);
        }
        catch { /* 비핵심 */ }
    }

    private static string GetAppLogPath() =>
        Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
            "AxCopilot", "logs");

    private static string FormatBytes(long bytes) => bytes switch
    {
        >= 1024L * 1024 * 1024 => $"{bytes / 1024.0 / 1024 / 1024:F1} GB",
        >= 1024L * 1024        => $"{bytes / 1024.0 / 1024:F1} MB",
        >= 1024L               => $"{bytes / 1024.0:F0} KB",
        _                      => $"{bytes} B",
    };
}
