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

using WinBitmapDecoder  = Windows.Graphics.Imaging.BitmapDecoder;
using WinBitmapPixelFmt = Windows.Graphics.Imaging.BitmapPixelFormat;
using WinSoftwareBitmap = Windows.Graphics.Imaging.SoftwareBitmap;
using WinOcrEngine       = Windows.Media.Ocr.OcrEngine;
using WinStorageFile     = Windows.Storage.StorageFile;
using WinFileAccessMode  = Windows.Storage.FileAccessMode;

namespace AxCopilot.Handlers;

/// <summary>
/// L5-2: 화면 텍스트 OCR 추출 핸들러.
/// 예: ocr          → 옵션 목록 (영역 선택 / 클립보드 이미지)
///     ocr region   → 드래그 영역 선택 후 텍스트 추출
///     ocr clip     → 클립보드 이미지에서 텍스트 추출
/// 결과 텍스트는 클립보드에 복사되고 런처 입력창에 채워집니다.
/// </summary>
public class OcrHandler : IActionHandler
{
    public string? Prefix => "ocr";

    public PluginMetadata Metadata => new(
        "OcrExtractor",
        "화면 텍스트 추출 (OCR)",
        "1.0",
        "AX");

    private const string DataRegion    = "__ocr_region__";
    private const string DataClipboard = "__ocr_clipboard__";

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

        var items = new List<LauncherItem>
        {
            new LauncherItem(
                "화면 영역 텍스트 추출",
                "드래그로 영역을 선택하면 텍스트를 자동으로 인식합니다  ·  F4 단축키 지원",
                null, DataRegion,
                Symbol: "\uE8D2"),

            new LauncherItem(
                "클립보드 이미지 텍스트 추출",
                "클립보드에 복사된 이미지에서 텍스트를 인식합니다",
                null, DataClipboard,
                Symbol: "\uE77F")
        };

        // 쿼리 필터링
        if (!string.IsNullOrEmpty(q))
        {
            items = items.Where(i =>
                i.Title.Contains(q, StringComparison.OrdinalIgnoreCase) ||
                i.Subtitle.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();
        }

        // OCR 미지원 안내
        if (WinOcrEngine.TryCreateFromUserProfileLanguages() == null)
        {
            items.Clear();
            items.Add(new LauncherItem(
                "OCR 기능을 사용할 수 없습니다",
                "Windows 설정 → 언어에서 OCR 지원 언어 팩을 설치하세요",
                null, null,
                Symbol: Symbols.Info));
        }

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

    public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data as string)
        {
            case DataRegion:
                await ExecuteRegionOcrAsync(ct);
                break;
            case DataClipboard:
                await ExecuteClipboardOcrAsync(ct);
                break;
        }
    }

    // ─── 영역 선택 OCR ───────────────────────────────────────────────────────

    private static async Task ExecuteRegionOcrAsync(CancellationToken ct)
    {
        // 런처가 완전히 사라질 때까지 대기
        await Task.Delay(180, ct);

        System.Drawing.Rectangle? selected  = null;
        Bitmap?                   fullBmp   = null;

        // UI 스레드에서 오버레이 창 표시
        await Application.Current.Dispatcher.InvokeAsync(() =>
        {
            var bounds = GetAllScreenBounds();
            fullBmp = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb);
            using var g = Graphics.FromImage(fullBmp);
            g.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy);

            var overlay = new Views.RegionSelectWindow(fullBmp, bounds);
            overlay.ShowDialog();
            selected = overlay.SelectedRect;
        });

        if (selected == null || selected.Value.Width < 8 || selected.Value.Height < 8)
        {
            fullBmp?.Dispose();
            NotificationService.Notify("AX Copilot", "영역 선택이 취소되었습니다.");
            return;
        }

        // 선택 영역 크롭
        var r   = selected.Value;
        using var crop = new Bitmap(r.Width, r.Height, PixelFormat.Format32bppArgb);
        using (var cg = Graphics.FromImage(crop))
            cg.DrawImage(fullBmp!, new System.Drawing.Rectangle(0, 0, r.Width, r.Height), r, System.Drawing.GraphicsUnit.Pixel);
        fullBmp?.Dispose();

        // OCR 실행
        var text = await RunOcrOnBitmapAsync(crop);

        // 결과 처리
        HandleOcrResult(text, $"{r.Width}×{r.Height} 영역");
    }

    // ─── 클립보드 이미지 OCR ─────────────────────────────────────────────────

    private static async Task ExecuteClipboardOcrAsync(CancellationToken ct)
    {
        Bitmap? clipBmp = null;

        await Application.Current.Dispatcher.InvokeAsync(() =>
        {
            if (Clipboard.ContainsImage())
            {
                var src = Clipboard.GetImage();
                if (src != null)
                {
                    // BitmapSource → System.Drawing.Bitmap 변환
                    var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
                    encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(src));
                    using var ms = new MemoryStream();
                    encoder.Save(ms);
                    ms.Position = 0;
                    clipBmp = new Bitmap(ms);
                }
            }
        });

        if (clipBmp == null)
        {
            NotificationService.Notify("AX Copilot — OCR", "클립보드에 이미지가 없습니다.");
            return;
        }

        using (clipBmp)
        {
            var text = await RunOcrOnBitmapAsync(clipBmp);
            HandleOcrResult(text, "클립보드 이미지");
        }
    }

    // ─── 공통: Bitmap → OCR ─────────────────────────────────────────────────

    private static async Task<string?> RunOcrOnBitmapAsync(Bitmap bmp)
    {
        var engine = WinOcrEngine.TryCreateFromUserProfileLanguages();
        if (engine == null) return null;

        // Bitmap을 임시 PNG로 저장
        var tmpPath = Path.Combine(Path.GetTempPath(), $"axocr_{Guid.NewGuid():N}.png");
        try
        {
            bmp.Save(tmpPath, ImageFormat.Png);

            var storageFile = await WinStorageFile.GetFileFromPathAsync(tmpPath);
            using var stream  = await storageFile.OpenAsync(WinFileAccessMode.Read);
            var decoder = await WinBitmapDecoder.CreateAsync(stream);

            WinSoftwareBitmap? origBitmap = null;
            WinSoftwareBitmap? ocrBitmap  = null;
            try
            {
                origBitmap = await decoder.GetSoftwareBitmapAsync();
                ocrBitmap  = origBitmap.BitmapPixelFormat == WinBitmapPixelFmt.Bgra8
                    ? origBitmap
                    : WinSoftwareBitmap.Convert(origBitmap, WinBitmapPixelFmt.Bgra8);

                var result = await engine.RecognizeAsync(ocrBitmap);
                var text   = result.Text?.Trim();
                if (text?.Length > 5_000) text = text[..5_000];
                return string.IsNullOrWhiteSpace(text) ? null : text;
            }
            finally
            {
                if (!ReferenceEquals(origBitmap, ocrBitmap)) origBitmap?.Dispose();
                ocrBitmap?.Dispose();
            }
        }
        catch (Exception ex)
        {
            LogService.Warn($"OCR 실행 오류: {ex.Message}");
            return null;
        }
        finally
        {
            try { if (File.Exists(tmpPath)) File.Delete(tmpPath); } catch { /* ignore */ }
        }
    }

    // ─── 공통: 결과 처리 ────────────────────────────────────────────────────

    private static void HandleOcrResult(string? text, string source)
    {
        if (string.IsNullOrWhiteSpace(text))
        {
            NotificationService.Notify("OCR 완료", $"{source}에서 텍스트를 인식하지 못했습니다.");
            return;
        }

        // 클립보드에 복사
        Application.Current?.Dispatcher.Invoke(() =>
        {
            Clipboard.SetText(text);
        });

        // 런처를 다시 열고 결과 텍스트를 입력창에 채움
        Application.Current?.Dispatcher.BeginInvoke(() =>
        {
            var launcher = Application.Current?.Windows
                .OfType<Views.LauncherWindow>().FirstOrDefault();
            if (launcher != null)
            {
                launcher.SetInputText(text.Length > 200 ? text[..200] : text);
                launcher.Show();
            }
        }, System.Windows.Threading.DispatcherPriority.Background);

        // 완료 알림
        var preview = text.Length > 60 ? text[..57].Replace('\n', ' ') + "…" : text.Replace('\n', ' ');
        NotificationService.Notify("OCR 완료", $"클립보드 복사됨: {preview}");
        LogService.Info($"OCR 성공 ({source}, {text.Length}자)");
    }

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

    private static System.Drawing.Rectangle GetAllScreenBounds()
    {
        var bounds = System.Drawing.Rectangle.Empty;
        foreach (System.Windows.Forms.Screen screen in System.Windows.Forms.Screen.AllScreens)
            bounds = System.Drawing.Rectangle.Union(bounds, screen.Bounds);
        return bounds;
    }
}
