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

namespace AxCopilot.Handlers;

/// <summary>
/// L13-3: 드라이브 정보 핸들러. "drive" 프리픽스로 사용합니다.
///
/// 예: drive               → 전체 드라이브 목록 + 용량 요약
///     drive C             → C 드라이브 상세 정보
///     drive C:\           → 경로 형식도 지원
///     drive large         → 사용량 많은 순서로 정렬
/// Enter → 드라이브 정보를 클립보드에 복사.
/// </summary>
public class DriveHandler : IActionHandler
{
    public string? Prefix => "drive";

    public PluginMetadata Metadata => new(
        "Drive",
        "드라이브 정보 — 용량 · 파일시스템 · 여유공간",
        "1.0",
        "AX");

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

        var drives = GetDrives();

        if (string.IsNullOrWhiteSpace(q))
        {
            var totalSize  = drives.Sum(d => d.TotalSize);
            var totalFree  = drives.Sum(d => d.AvailableFree);
            var totalUsed  = totalSize - totalFree;

            items.Add(new LauncherItem(
                $"드라이브  {drives.Count}개",
                $"전체 {FormatBytes(totalSize)}  ·  사용 {FormatBytes(totalUsed)}  ·  여유 {FormatBytes(totalFree)}",
                null, null, Symbol: "\uEDA2"));

            foreach (var d in drives.OrderBy(d => d.Name))
                items.Add(MakeDriveSummaryItem(d));

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

        var sub = q.ToUpperInvariant().TrimEnd(':', '\\', '/');

        if (sub == "LARGE")
        {
            // 사용량 많은 순
            foreach (var d in drives.OrderByDescending(d => d.UsedSpace))
                items.Add(MakeDriveSummaryItem(d));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 특정 드라이브 상세
        var target = drives.FirstOrDefault(d =>
            d.Name.StartsWith(sub, StringComparison.OrdinalIgnoreCase));

        if (target == null)
        {
            items.Add(new LauncherItem("드라이브 없음", $"'{q}' 드라이브를 찾을 수 없습니다", null, null, Symbol: "\uE783"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is ("copy", string text))
        {
            try
            {
                System.Windows.Application.Current.Dispatcher.Invoke(
                    () => Clipboard.SetText(text));
                NotificationService.Notify("Drive", "클립보드에 복사했습니다.");
            }
            catch { /* 비핵심 */ }
        }
        return Task.CompletedTask;
    }

    // ── 드라이브 정보 수집 ────────────────────────────────────────────────────

    private record DriveInfo2(
        string Name,
        string VolumeLabel,
        string DriveFormat,
        DriveType DriveType,
        long TotalSize,
        long AvailableFree,
        long UsedSpace,
        bool IsReady);

    private static List<DriveInfo2> GetDrives()
    {
        return DriveInfo.GetDrives()
            .Select(d =>
            {
                if (!d.IsReady)
                    return new DriveInfo2(d.Name, "", "", d.DriveType, 0, 0, 0, false);
                try
                {
                    return new DriveInfo2(
                        d.Name,
                        d.VolumeLabel,
                        d.DriveFormat,
                        d.DriveType,
                        d.TotalSize,
                        d.AvailableFreeSpace,
                        d.TotalSize - d.AvailableFreeSpace,
                        true);
                }
                catch
                {
                    return new DriveInfo2(d.Name, "", d.DriveFormat, d.DriveType, 0, 0, 0, false);
                }
            })
            .ToList();
    }

    private static IEnumerable<LauncherItem> BuildDetailItems(DriveInfo2 d)
    {
        var usagePercent = d.TotalSize > 0 ? (double)d.UsedSpace / d.TotalSize * 100 : 0;
        var bar          = MakeBar(usagePercent, 20);
        var summary      = $"""
            드라이브:     {d.Name}
            볼륨 레이블:  {(string.IsNullOrEmpty(d.VolumeLabel) ? "(없음)" : d.VolumeLabel)}
            파일 시스템:  {d.DriveFormat}
            드라이브 종류: {DriveTypeName(d.DriveType)}
            전체 용량:    {FormatBytes(d.TotalSize)}
            사용 중:      {FormatBytes(d.UsedSpace)} ({usagePercent:F1}%)
            여유 공간:    {FormatBytes(d.AvailableFree)}
            """;

        yield return new LauncherItem(
            $"{d.Name}  {FormatBytes(d.TotalSize)}",
            $"사용 {usagePercent:F0}%  {bar}  여유 {FormatBytes(d.AvailableFree)}",
            null, ("copy", summary), Symbol: "\uEDA2");

        yield return new LauncherItem("볼륨 레이블",   string.IsNullOrEmpty(d.VolumeLabel) ? "(없음)" : d.VolumeLabel, null, null, Symbol: "\uEDA2");
        yield return new LauncherItem("파일 시스템",   d.DriveFormat,                         null, null, Symbol: "\uEDA2");
        yield return new LauncherItem("드라이브 종류", DriveTypeName(d.DriveType),            null, null, Symbol: "\uEDA2");
        yield return new LauncherItem("전체 용량",     FormatBytes(d.TotalSize),              null, ("copy", FormatBytes(d.TotalSize)),     Symbol: "\uEDA2");
        yield return new LauncherItem("사용 중",       $"{FormatBytes(d.UsedSpace)} ({usagePercent:F1}%)", null, ("copy", FormatBytes(d.UsedSpace)), Symbol: "\uEDA2");
        yield return new LauncherItem("여유 공간",     FormatBytes(d.AvailableFree),          null, ("copy", FormatBytes(d.AvailableFree)), Symbol: "\uEDA2");
    }

    private static LauncherItem MakeDriveSummaryItem(DriveInfo2 d)
    {
        if (!d.IsReady)
            return new LauncherItem(d.Name, $"준비 안됨 ({DriveTypeName(d.DriveType)})", null, null, Symbol: "\uEDA2");

        var usagePercent = d.TotalSize > 0 ? (double)d.UsedSpace / d.TotalSize * 100 : 0;
        var bar          = MakeBar(usagePercent, 12);
        var label        = string.IsNullOrEmpty(d.VolumeLabel) ? d.Name : $"{d.Name} ({d.VolumeLabel})";

        return new LauncherItem(
            label,
            $"{bar} {usagePercent:F0}%  ·  여유 {FormatBytes(d.AvailableFree)} / {FormatBytes(d.TotalSize)}",
            null,
            ("copy", $"{d.Name} {FormatBytes(d.TotalSize)} 사용{usagePercent:F0}% 여유{FormatBytes(d.AvailableFree)}"),
            Symbol: "\uEDA2");
    }

    // ── 유틸 ─────────────────────────────────────────────────────────────────

    private static string MakeBar(double percent, int width)
    {
        var filled = (int)(percent / 100.0 * width);
        filled = Math.Clamp(filled, 0, width);
        return "[" + new string('█', filled) + new string('░', width - filled) + "]";
    }

    private static string DriveTypeName(DriveType dt) => dt switch
    {
        DriveType.Fixed        => "고정 디스크",
        DriveType.Removable    => "이동식 디스크",
        DriveType.Network      => "네트워크 드라이브",
        DriveType.CDRom        => "CD/DVD",
        DriveType.Ram          => "RAM 디스크",
        DriveType.NoRootDirectory => "루트 없음",
        _                      => "알 수 없음",
    };

    private static string FormatBytes(long bytes) => bytes switch
    {
        >= 1024L * 1024 * 1024 * 1024 => $"{bytes / 1024.0 / 1024 / 1024 / 1024:F2} TB",
        >= 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",
    };
}
