using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace AxCopilot.Views;

/// <summary>
/// 모던 카드 스타일 트레이 컨텍스트 메뉴 팩토리.
/// 배경색은 현재 WPF 테마 리소스를 실시간으로 읽어 적용합니다.
/// </summary>
internal static class TrayContextMenu
{
    // Segoe MDL2 Assets 글리프 상수
    internal const string GlyphOpen     = "\uE7C5"; // Launch
    internal const string GlyphSettings = "\uE713"; // Settings
    internal const string GlyphReload   = "\uE72C"; // Refresh
    internal const string GlyphFolder   = "\uE838"; // Folder
    internal const string GlyphInfo     = "\uE946"; // Info
    internal const string GlyphStats    = "\uE9D9"; // Chart
    internal const string GlyphChat     = "\uE8BD"; // Chat
    internal const string GlyphGuide    = "\uE736"; // ReadingList (사용 가이드)
    internal const string GlyphAutoRun  = "\uE82F"; // Lightbulb (전구)
    internal const string GlyphExit     = "\uE711"; // Cancel

    // 1×1 투명 더미 이미지 — OnRenderItemImage 콜백을 강제로 트리거하기 위함
    private static readonly System.Drawing.Bitmap DummyImage = new(1, 1);

    /// <summary>
    /// 현재 화면의 DPI 배율을 반환합니다 (100% = 1.0, 150% = 1.5).
    /// WinForms는 논리 픽셀 값을 DPI 배율만큼 자동 확대하므로,
    /// 이 값으로 역산하여 모든 PC에서 동일한 물리적 크기를 유지합니다.
    /// </summary>
    private static float GetDpiScale()
    {
        try
        {
            using var g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero);
            return Math.Max(1f, g.DpiX / 96f);
        }
        catch (Exception) { return 1f; }
    }

    /// <summary>논리 픽셀 값을 DPI 역산하여 물리적 크기가 동일하게 유지되도록 변환합니다.</summary>
    private static int Dp(int logicalPx, float dpiScale) =>
        Math.Max(1, (int)Math.Round(logicalPx / dpiScale));

    /// <summary>외부에서 DPI 보정된 Padding을 생성할 때 사용합니다.</summary>
    public static System.Windows.Forms.Padding DpiPadding(int left, int top, int right, int bottom)
    {
        var s = GetDpiScale();
        return new System.Windows.Forms.Padding(Dp(left, s), Dp(top, s), Dp(right, s), Dp(bottom, s));
    }

    public static ToolStripMenuItem MakeItem(string text, string glyph, EventHandler onClick)
    {
        var s    = GetDpiScale();
        var item = new ToolStripMenuItem(text)
        {
            Tag     = glyph,
            Image   = DummyImage, // Image가 있어야 OnRenderItemImage가 호출됨
            Padding = new Padding(Dp(4, s), Dp(10, s), Dp(16, s), Dp(10, s)),
        };
        item.Click += onClick;
        return item;
    }

    /// <summary>패딩이 적용된 ContextMenuStrip을 생성합니다.</summary>
    public static ContextMenuStrip CreateMenu()
    {
        var s    = GetDpiScale();
        var menu = new ContextMenuStrip();
        menu.Renderer         = new ModernTrayRenderer();
        // Point 단위 폰트는 DPI 자동 확대되므로 역산 적용
        // Point 단위는 DPI와 무관하게 동일한 물리 크기 → 역산하지 않음
        menu.Font             = new Font("Segoe UI", 10f, GraphicsUnit.Point);
        menu.ShowImageMargin  = true;
        // 너비를 넉넉히 잡아 좌측 아이콘~테두리 간 여백 확보
        menu.ImageScalingSize = new Size(Dp(52, s), Dp(32, s));
        menu.MinimumSize      = new Size(Dp(280, s), 0);

        // 팝업이 열릴 때 모서리를 둥글게 클리핑
        menu.Opened += (_, _) => ApplyRoundedCorners(menu);
        return menu;
    }

    private static void ApplyRoundedCorners(ContextMenuStrip menu)
    {
        try
        {
            var rgn = CreateRoundRectRgn(0, 0, menu.Width, menu.Height, 16, 16);
            if (rgn == IntPtr.Zero) return;
            // SetWindowRgn 성공 시 시스템이 핸들 소유권을 가져감 → DeleteObject 불필요
            // 실패 시 직접 해제해야 GDI 누수 방지
            if (SetWindowRgn(menu.Handle, rgn, true) == 0)
                DeleteObject(rgn);
        }
        catch (Exception) { /* 클리핑 실패 시 사각형으로 폴백 */ }
    }

    [DllImport("gdi32.dll")]
    private static extern IntPtr CreateRoundRectRgn(int x1, int y1, int x2, int y2, int cx, int cy);

    [DllImport("gdi32.dll")]
    private static extern bool DeleteObject(IntPtr hObject);

    [DllImport("user32.dll")]
    private static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw);

    /// <summary>
    /// 모든 아이템 추가 후 호출하여 상하 테두리 여백을 적용합니다.
    /// WinForms ContextMenuStrip은 Padding/DefaultPadding/DisplayRectangle 모두
    /// 내부 레이아웃이 무시하므로, 첫/마지막 아이템의 Margin으로 처리합니다.
    /// </summary>
    public static void ApplySpacing(ContextMenuStrip menu, int top = 10, int bottom = 10, int left = 0, int right = 0)
    {
        if (menu.Items.Count == 0) return;
        var s = GetDpiScale();
        int t = Dp(top, s), b = Dp(bottom, s), l = Dp(left, s), r = Dp(right, s);

        foreach (ToolStripItem item in menu.Items)
        {
            var m = item.Margin;
            item.Margin = new Padding(m.Left + l, m.Top, m.Right + r, m.Bottom);
        }
        var first = menu.Items[0];
        first.Margin = new Padding(first.Margin.Left, t, first.Margin.Right, first.Margin.Bottom);
        var last = menu.Items[menu.Items.Count - 1];
        last.Margin = new Padding(last.Margin.Left, last.Margin.Top, last.Margin.Right, b);
    }
}

// ─────────────────────────────────────────────────────────────────────────────

internal sealed class ModernTrayRenderer : ToolStripProfessionalRenderer
{
    // 전구(자동 실행) 활성 색상 — 앰버 글로우
    private static readonly Color BulbOnColor  = Color.FromArgb(255, 185, 0);
    private static readonly Color BulbGlowHalo = Color.FromArgb(50, 255, 185, 0);

    public ModernTrayRenderer() : base(new ModernColorTable()) { }

    // ─── 테마 색상 리더 ─────────────────────────────────────────────────

    private static Color ThemeColor(string key, Color fallback)
    {
        try
        {
            if (System.Windows.Application.Current?.Resources[key]
                is System.Windows.Media.SolidColorBrush b)
                return Color.FromArgb(b.Color.A, b.Color.R, b.Color.G, b.Color.B);
        }
        catch (Exception) { }
        return fallback;
    }

    private static Color BgColor      => ThemeColor("LauncherBackground",    Color.FromArgb(250, 250, 252));
    private static Color HoverColor   => ThemeColor("ItemHoverBackground",   Color.FromArgb(234, 234, 247));
    private static Color AccentColor  => ThemeColor("AccentColor",           Color.FromArgb(75, 94, 252));
    private static Color TextColor    => ThemeColor("PrimaryText",           Color.FromArgb(22, 23, 42));
    private static Color TextDimColor => ThemeColor("SecondaryText",         Color.FromArgb(90, 92, 128));
    private static Color SepColor     => ThemeColor("SeparatorColor",        Color.FromArgb(228, 228, 242));
    private static Color BorderColor  => ThemeColor("BorderColor",           Color.FromArgb(210, 210, 232));
    private static Color IconColor    => ThemeColor("SecondaryText",         Color.FromArgb(110, 112, 148));

    // ─── 배경 ────────────────────────────────────────────────────────────

    protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
    {
        using var br = new SolidBrush(BgColor);
        e.Graphics.FillRectangle(br, e.AffectedBounds);
    }

    protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
    {
        var g = e.Graphics;
        g.SmoothingMode = SmoothingMode.AntiAlias;
        using var pen  = new Pen(BorderColor, 1f);
        // ApplyRoundedCorners 의 clip radius(14) 보다 0.5px 안쪽에 그려야
        // 창 경계 밖으로 삐져나오지 않음
        var rect = new RectangleF(0.5f, 0.5f,
                                  e.ToolStrip.Width  - 1f,
                                  e.ToolStrip.Height - 1f);
        using var path = BuildRoundedPath(rect, 15f);
        g.DrawPath(pen, path);
        g.SmoothingMode = SmoothingMode.Default;
    }

    protected override void OnRenderImageMargin(ToolStripRenderEventArgs e)
    {
        // 거터 없음 — 전체 배경과 동일한 색
        using var br = new SolidBrush(BgColor);
        e.Graphics.FillRectangle(br, e.AffectedBounds);
    }

    // ─── 아이템 배경 ─────────────────────────────────────────────────────

    protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
    {
        var g    = e.Graphics;
        var item = e.Item;

        // 기본 배경 (항상 메뉴 배경색으로 초기화)
        using var bg = new SolidBrush(BgColor);
        g.FillRectangle(bg, 0, 0, item.Width, item.Height);

        if (!item.Selected || !item.Enabled) return;

        // 호버: 안쪽에 둥근 모서리 하이라이트
        g.SmoothingMode = SmoothingMode.AntiAlias;
        using var hoverBr = new SolidBrush(HoverColor);
        DrawRoundedFill(g, hoverBr, new RectangleF(6, 2, item.Width - 12, item.Height - 4), 8f);
        g.SmoothingMode = SmoothingMode.Default;
    }

    // ─── 구분선 ──────────────────────────────────────────────────────────

    protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
    {
        int y = e.Item.Height / 2;
        using var pen = new Pen(SepColor);
        e.Graphics.DrawLine(pen, 16, y, e.Item.Width - 16, y);
    }

    // ─── 텍스트 ──────────────────────────────────────────────────────────

    protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
    {
        e.TextColor = e.Item.Enabled ? TextColor : TextDimColor;
        e.TextFormat = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
        base.OnRenderItemText(e);
    }

    // ─── 아이콘 (일반 아이템 + CheckOnClick 모두 처리) ───────────────────

    protected override void OnRenderItemImage(ToolStripItemImageRenderEventArgs e)
    {
        // 모든 아이템의 글리프를 여기서 그린다
        DrawGlyph(e.Graphics, e.Item, e.ImageRectangle);
    }

    protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
    {
        // CheckOnClick 항목: 기본 체크마크 대신 글리프 아이콘을 그린다
        DrawGlyph(e.Graphics, e.Item, e.ImageRectangle);
    }

    // ─── 글리프 렌더러 ───────────────────────────────────────────────────

    private static void DrawGlyph(Graphics g, ToolStripItem item, Rectangle bounds)
    {
        if (item.Tag is not string glyph || string.IsNullOrEmpty(glyph)) return;
        if (bounds.Width <= 0 || bounds.Height <= 0) return;

        g.TextRenderingHint = TextRenderingHint.AntiAlias;

        bool isLightbulb = glyph == TrayContextMenu.GlyphAutoRun;
        bool isChecked   = item is ToolStripMenuItem { Checked: true };

        Color glyphColor;
        if (isLightbulb && isChecked)
        {
            // 전구 켜짐 — 앰버 글로우 효과
            DrawLightbulbGlow(g, glyph, bounds);
            glyphColor = BulbOnColor;
        }
        else if (isLightbulb && !isChecked)
        {
            // 전구 꺼짐 — 확실히 구분되는 진한 회색
            glyphColor = Color.FromArgb(120, 120, 140);
        }
        else if (item.Selected && item.Enabled)
        {
            glyphColor = AccentColor;
        }
        else
        {
            glyphColor = IconColor;
        }

        // Point 단위는 DPI와 무관하게 동일한 물리 크기 → 역산하지 않음
        using var font = new Font("Segoe MDL2 Assets", 12f, GraphicsUnit.Point);
        using var br   = new SolidBrush(glyphColor);
        var fmt  = StringFormat.GenericTypographic;
        var size = g.MeasureString(glyph, font, 0, fmt);
        // 넓은 아이콘 영역 내 중앙 정렬
        float x  = bounds.X + (bounds.Width  - size.Width)  / 2f + 2f;
        float y  = bounds.Y + (bounds.Height - size.Height) / 2f;
        g.DrawString(glyph, font, br, x, y, fmt);
    }

    private static void DrawLightbulbGlow(Graphics g, string glyph, Rectangle bounds)
    {
        // 중심에서 균일하게 퍼지는 원형 앰버 글로우
        g.SmoothingMode = SmoothingMode.AntiAlias;
        float cx = bounds.X + bounds.Width  / 2f;
        float cy = bounds.Y + bounds.Height / 2f;
        float radius = Math.Max(bounds.Width, bounds.Height) * 0.85f;

        var glowRect = new RectangleF(cx - radius, cy - radius, radius * 2, radius * 2);
        using var path = new GraphicsPath();
        path.AddEllipse(glowRect);
        using var brush = new PathGradientBrush(path)
        {
            CenterColor    = Color.FromArgb(60, 255, 185, 0),
            SurroundColors = new[] { Color.FromArgb(0, 255, 185, 0) },
            CenterPoint    = new PointF(cx, cy)
        };
        g.FillEllipse(brush, glowRect);
        g.SmoothingMode = SmoothingMode.Default;
    }

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

    private static GraphicsPath BuildRoundedPath(RectangleF rect, float radius)
    {
        float d    = radius * 2f;
        var   path = new GraphicsPath();
        path.AddArc(rect.X,           rect.Y,            d, d, 180, 90);
        path.AddArc(rect.Right - d,   rect.Y,            d, d, 270, 90);
        path.AddArc(rect.Right - d,   rect.Bottom - d,   d, d,   0, 90);
        path.AddArc(rect.X,           rect.Bottom - d,   d, d,  90, 90);
        path.CloseFigure();
        return path;
    }

    private static void DrawRoundedFill(Graphics g, Brush brush, RectangleF rect, float radius)
    {
        using var path = BuildRoundedPath(rect, radius);
        g.FillPath(brush, path);
    }
}

// ─────────────────────────────────────────────────────────────────────────────

internal sealed class ModernColorTable : ProfessionalColorTable
{
    private static Color TC(string key, Color fb)
    {
        try
        {
            if (System.Windows.Application.Current?.Resources[key]
                is System.Windows.Media.SolidColorBrush b)
                return Color.FromArgb(b.Color.A, b.Color.R, b.Color.G, b.Color.B);
        }
        catch (Exception) { }
        return fb;
    }

    private static Color Bg     => TC("LauncherBackground", Color.FromArgb(250, 250, 252));
    private static Color Hover  => TC("ItemHoverBackground", Color.FromArgb(234, 234, 247));
    private static Color Border => TC("BorderColor", Color.FromArgb(210, 210, 232));
    private static Color Sep    => TC("SeparatorColor", Color.FromArgb(228, 228, 242));

    public override Color MenuBorder                    => Border;
    public override Color ToolStripDropDownBackground   => Bg;
    public override Color ImageMarginGradientBegin      => Bg;
    public override Color ImageMarginGradientMiddle     => Bg;
    public override Color ImageMarginGradientEnd        => Bg;
    public override Color MenuItemSelected              => Hover;
    public override Color MenuItemSelectedGradientBegin => Hover;
    public override Color MenuItemSelectedGradientEnd   => Hover;
    public override Color MenuItemBorder                => Color.Transparent;
    public override Color MenuItemPressedGradientBegin  => Hover;
    public override Color MenuItemPressedGradientEnd    => Hover;
    public override Color SeparatorLight                => Sep;
    public override Color SeparatorDark                 => Sep;
    public override Color CheckBackground               => Color.Transparent;
    public override Color CheckSelectedBackground       => Color.Transparent;
    public override Color CheckPressedBackground        => Color.Transparent;
}

