using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace AxCopilot.Views;

/// <summary>
/// WPF 기반 커스텀 트레이 컨텍스트 메뉴.
/// WinForms ContextMenuStrip의 DPI 불일치 문제를 근본 해결합니다.
/// </summary>
public partial class TrayMenuWindow : Window
{
    private System.Windows.Threading.DispatcherTimer? _autoCloseTimer;

    public TrayMenuWindow()
    {
        InitializeComponent();

        // 마우스가 메뉴 밖으로 나가면 일정 시간 후 자동 닫힘
        MouseLeave += (_, _) =>
        {
            _autoCloseTimer?.Stop();
            _autoCloseTimer = new System.Windows.Threading.DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(400)
            };
            _autoCloseTimer.Tick += (_, _) => { _autoCloseTimer.Stop(); Hide(); };
            _autoCloseTimer.Start();
        };

        // 마우스가 다시 메뉴 위로 오면 타이머 취소
        MouseEnter += (_, _) =>
        {
            _autoCloseTimer?.Stop();
        };
    }

    // ─── 아이템 빌더 API ─────────────────────────────────────────────────

    /// <summary>일반 메뉴 항목을 추가합니다.</summary>
    public TrayMenuWindow AddItem(string glyph, string text, Action onClick)
    {
        var item = CreateItemBorder(glyph, text);
        item.MouseLeftButtonUp += (_, _) => { Hide(); onClick(); };
        MenuPanel.Children.Add(item);
        return this;
    }

    /// <summary>일반 메뉴 항목을 추가하고 Border 참조를 반환합니다 (동적 가시성 제어용).</summary>
    public TrayMenuWindow AddItem(string glyph, string text, Action onClick, out Border itemRef)
    {
        var item = CreateItemBorder(glyph, text);
        item.MouseLeftButtonUp += (_, _) => { Hide(); onClick(); };
        MenuPanel.Children.Add(item);
        itemRef = item;
        return this;
    }

    // 전구 아이콘 활성 색상 — 앰버(노란) 글로우
    private static readonly Brush BulbOnBrush  = new SolidColorBrush(Color.FromRgb(255, 185, 0));
    private static readonly Brush BulbOffBrush = new SolidColorBrush(Color.FromRgb(120, 120, 140));

    /// <summary>토글(체크) 메뉴 항목을 추가합니다.</summary>
    public TrayMenuWindow AddToggleItem(string glyph, string text, bool initialChecked,
        Action<bool> onToggle, out Func<bool> getChecked, out Action<string> setText)
    {
        bool isChecked = initialChecked;
        var glyphBlock = new TextBlock
        {
            Text = glyph,
            FontFamily = ThemeResourceHelper.SegoeMdl2,
            FontSize = 14,
            Foreground = isChecked ? BulbOnBrush : BulbOffBrush,
            VerticalAlignment = VerticalAlignment.Center,
            Width = 20,
            TextAlignment = TextAlignment.Center,
        };

        // 켜진 상태에서 글로우 이펙트 적용
        if (isChecked)
            glyphBlock.Effect = new System.Windows.Media.Effects.DropShadowEffect
            {
                Color = Color.FromRgb(255, 185, 0), BlurRadius = 12, ShadowDepth = 0, Opacity = 0.7
            };

        var label = new TextBlock
        {
            Text = text,
            FontSize = 13,
            VerticalAlignment = VerticalAlignment.Center,
        };
        label.SetResourceReference(TextBlock.ForegroundProperty, "PrimaryText");

        var panel = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Children = { glyphBlock, label },
        };

        var border = new Border
        {
            Child = panel,
            CornerRadius = new CornerRadius(6),
            Padding = new Thickness(12, 8, 16, 8),
            Cursor = Cursors.Hand,
            Background = Brushes.Transparent,
        };

        border.MouseEnter += (_, _) =>
            border.Background = TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
        border.MouseLeave += (_, _) =>
            border.Background = Brushes.Transparent;

        border.MouseLeftButtonUp += (_, _) =>
        {
            isChecked = !isChecked;
            glyphBlock.Foreground = isChecked ? BulbOnBrush : BulbOffBrush;
            glyphBlock.Effect = isChecked
                ? new System.Windows.Media.Effects.DropShadowEffect
                  { Color = Color.FromRgb(255, 185, 0), BlurRadius = 12, ShadowDepth = 0, Opacity = 0.7 }
                : null;
            onToggle(isChecked);
        };

        getChecked = () => isChecked;
        setText = t => label.Text = t;
        MenuPanel.Children.Add(border);
        return this;
    }

    /// <summary>구분선을 추가합니다.</summary>
    public TrayMenuWindow AddSeparator()
    {
        var sep = new Border
        {
            Height = 1,
            Margin = new Thickness(16, 5, 16, 5),
        };
        sep.SetResourceReference(Border.BackgroundProperty, "SeparatorColor");
        MenuPanel.Children.Add(sep);
        return this;
    }

    // ─── 팝업 표시 ────────────────────────────────────────────────────────

    /// <summary>트레이 아이콘 근처에 메뉴를 표시합니다.</summary>
    public void ShowAtTray()
    {
        var workArea = SystemParameters.WorkArea;

        // 먼저 표시하여 ActualWidth/ActualHeight 확정
        Opacity = 0;
        Show();
        UpdateLayout();

        double menuW = ActualWidth;
        double menuH = ActualHeight;

        // 마우스 커서 위치 (물리 픽셀 → WPF 논리 좌표)
        var cursorPos = GetCursorPosition();
        double dpiScale = VisualTreeHelper.GetDpi(this).PixelsPerDip;
        double cx = cursorPos.X / dpiScale;
        double cy = cursorPos.Y / dpiScale;

        // 메뉴 우하단이 커서에서 살짝 떨어지도록 배치
        double left = cx - menuW - 8;
        double top  = cy - menuH - 8;

        // 화면 밖 보정
        if (left < workArea.Left) left = workArea.Left + 4;
        if (top < workArea.Top) top = workArea.Top + 4;
        if (left + menuW > workArea.Right) left = workArea.Right - menuW - 4;
        if (top + menuH > workArea.Bottom) top = workArea.Bottom - menuH - 4;

        Left = left;
        Top  = top;

        // 활성화하여 Deactivated 이벤트가 정상 작동하도록 보장
        Activate();

        // 페이드 인 애니메이션
        var fadeIn = new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(120))
        {
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
        };
        BeginAnimation(OpacityProperty, fadeIn);
    }

    /// <summary>메뉴를 표시하기 직전에 동적 항목을 갱신할 수 있는 이벤트.</summary>
    public event Action? Opening;

    /// <summary>Opening 이벤트를 트리거하고 메뉴를 표시합니다.</summary>
    public void ShowWithUpdate()
    {
        Opening?.Invoke();
        ShowAtTray();
    }

    // ─── 내부 헬퍼 ────────────────────────────────────────────────────────

    private Border CreateItemBorder(string glyph, string text)
    {
        var glyphBlock = new TextBlock
        {
            Text = glyph,
            FontFamily = ThemeResourceHelper.SegoeMdl2,
            FontSize = 14,
            VerticalAlignment = VerticalAlignment.Center,
            Width = 20,
            TextAlignment = TextAlignment.Center,
        };
        glyphBlock.SetResourceReference(TextBlock.ForegroundProperty, "SecondaryText");

        var label = new TextBlock
        {
            Text = text,
            FontSize = 13,
            VerticalAlignment = VerticalAlignment.Center,
        };
        label.SetResourceReference(TextBlock.ForegroundProperty, "PrimaryText");

        var panel = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Children = { glyphBlock, label },
        };

        var border = new Border
        {
            Child = panel,
            CornerRadius = new CornerRadius(6),
            Padding = new Thickness(12, 8, 16, 8),
            Cursor = Cursors.Hand,
            Background = Brushes.Transparent,
        };

        border.MouseEnter += (_, _) =>
        {
            border.Background = TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
            glyphBlock.Foreground = TryFindResource("AccentColor") as Brush ?? Brushes.Blue;
        };
        border.MouseLeave += (_, _) =>
        {
            border.Background = Brushes.Transparent;
            glyphBlock.SetResourceReference(TextBlock.ForegroundProperty, "SecondaryText");
        };

        return border;
    }

    private void Window_Deactivated(object sender, EventArgs e)
    {
        Hide();
    }

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetCursorPos(out POINT lpPoint);

    [StructLayout(LayoutKind.Sequential)]
    private struct POINT { public int X; public int Y; }

    private static POINT GetCursorPosition()
    {
        GetCursorPos(out var pt);
        return pt;
    }
}
