using Ink_Canvas.Properties;
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Magnification;
using Windows.Win32.UI.WindowsAndMessaging;
using Point = System.Windows.Point;
using Rect = System.Windows.Rect;

namespace Ink_Canvas.Windows
{
    /// <summary>
    /// 使用 Win32 Magnification API (Magnification.dll)。
    /// </summary>
    internal class MagnifierWindow : Window
    {
        #region P/Invoke

        private const string MagnifierClassName = "Magnifier";
        private const int WS_CHILD = 0x40000000;
        private const int WS_VISIBLE = 0x10000000;

        //[StructLayout(LayoutKind.Sequential)]
        //private struct RECT { public int left, top, right, bottom; public RECT(int l, int t, int r, int b) { left = l; top = t; right = r; bottom = b; } }

        //[StructLayout(LayoutKind.Sequential)]
        //private struct MAGTRANSFORM
        //{
        //    public float m00, m01, m02;
        //    public float m10, m11, m12;
        //    public float m20, m21, m22;
        //}

        //[DllImport("user32.dll", SetLastError = true)]
        //private static extern IntPtr CreateWindowEx(int dwExStyle, string lpClassName, string lpWindowName, int dwStyle,
        //    int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);

        //[DllImport("user32.dll")] private static extern bool DestroyWindow(IntPtr hWnd);
        //[DllImport("user32.dll")] private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
        //[DllImport("user32.dll")] private static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);

        //[DllImport("Magnification.dll")] private static extern bool MagInitialize();
        //[DllImport("Magnification.dll")] private static extern bool MagUninitialize();
        //[DllImport("Magnification.dll")] private static extern bool MagSetWindowSource(IntPtr hwnd, RECT rect);
        //[DllImport("Magnification.dll")] private static extern bool MagSetWindowTransform(IntPtr hwnd, ref MAGTRANSFORM pTransform);
        //[DllImport("Magnification.dll")] private static extern bool MagSetWindowFilterList(IntPtr hwnd, int dwFilterMode, int count, IntPtr[] pHWND);
        //private const int MW_FILTERMODE_EXCLUDE = 0;

        #endregion

        #region 单例

        private static MagnifierWindow _instance;
        public static bool HasInstance => _instance != null;
        public static event EventHandler Closed2;

        public static void Show(float zoom)
        {
            if (_instance != null) { _instance.Activate(); _instance.Zoom = zoom; return; }
            _instance = new MagnifierWindow { Zoom = zoom };
            _instance.Closed += (s, e) =>
            {
                _instance = null;
                Closed2?.Invoke(null, EventArgs.Empty);
            };
            _instance.Show();
        }

        public static void HideInstance() => _instance?.Close();
        public static void SetZoom(float zoom) { if (_instance != null) _instance.Zoom = zoom; }

        #endregion

        // 选择框（放大区域）在 Canvas 中的几何属性 (DIP)
        private double _boxLeft = 200;
        private double _boxTop = 150;
        private double _boxWidth = 520;
        private double _boxHeight = 360;
        private const double MinBoxW = 200;
        private const double MinBoxH = 140;

        private System.Windows.Controls.Canvas _canvas;
        private Rectangle _overlay;          // 半透明遮罩
        private Border _selectionBorder;     // 白色边框选择框
        private MagnifierHost _magHost;
        private System.Windows.Controls.Border _toolbar;
        private Ellipse[] _handles;          // 8 个控点
        private ToggleButton _blackoutButton;
        private bool _blackoutOn;

        private IntPtr _magHwnd;
        private HwndSource _hwndSource;
        private DispatcherTimer _timer;
        private bool _magInitialized;

        private float _zoom = 2.0f;
        public float Zoom
        {
            get => _zoom;
            set
            {
                _zoom = Math.Max(1.1f, Math.Min(8.0f, value));
                if (_magHwnd != IntPtr.Zero) ApplyTransform();
            }
        }

        private MagnifierWindow()
        {
            Title = "聚焦放大镜";
            WindowStyle = WindowStyle.None;
            ResizeMode = ResizeMode.NoResize;
            AllowsTransparency = true;
            Background = Brushes.Transparent;
            Topmost = true;
            ShowInTaskbar = false;
            WindowState = WindowState.Maximized;

            _canvas = new System.Windows.Controls.Canvas { Background = Brushes.Transparent };

            // 半透明遮罩：固定浅色，挖空选择框
            _overlay = new Rectangle
            {
                Fill = new SolidColorBrush(Color.FromArgb(102, 0, 0, 0)),
                IsHitTestVisible = false
            };
            _canvas.Children.Add(_overlay);

            // 选择框
            _selectionBorder = new Border
            {
                BorderBrush = Brushes.White,
                BorderThickness = new Thickness(1.5),
                Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)), // 几乎透明，可命中
                Cursor = Cursors.SizeAll,
                SnapsToDevicePixels = true
            };
            _selectionBorder.MouseLeftButtonDown += SelectionBorder_MouseDown;
            _selectionBorder.MouseMove += SelectionBorder_MouseMove;
            _selectionBorder.MouseLeftButtonUp += SelectionBorder_MouseUp;
            _magHost = new MagnifierHost(this);
            _selectionBorder.Child = _magHost;
            _canvas.Children.Add(_selectionBorder);

            // 8 个控点
            _handles = new Ellipse[8];
            string[] tags = { "NW", "N", "NE", "E", "SE", "S", "SW", "W" };
            Cursor[] cursors = { Cursors.SizeNWSE, Cursors.SizeNS, Cursors.SizeNESW, Cursors.SizeWE,
                                 Cursors.SizeNWSE, Cursors.SizeNS, Cursors.SizeNESW, Cursors.SizeWE };
            for (int i = 0; i < 8; i++)
            {
                var h = new Ellipse
                {
                    Width = 12,
                    Height = 12,
                    Fill = Brushes.White,
                    Stroke = new SolidColorBrush(Color.FromArgb(220, 0, 0, 0)),
                    StrokeThickness = 1,
                    Cursor = cursors[i],
                    Tag = tags[i]
                };
                h.MouseLeftButtonDown += Handle_MouseDown;
                h.MouseMove += Handle_MouseMove;
                h.MouseLeftButtonUp += Handle_MouseUp;
                _handles[i] = h;
                _canvas.Children.Add(h);
            }

            _toolbar = BuildToolbar();
            _canvas.Children.Add(_toolbar);

            Content = _canvas;

            Loaded += (s, e) =>
            {
                LayoutAll();
            };
            SizeChanged += (s, e) => LayoutAll();
            KeyDown += (s, e) => { if (e.Key == Key.Escape) Close(); };
        }

        private System.Windows.Controls.Border BuildToolbar()
        {
            var bar = new System.Windows.Controls.Border
            {
                Background = new SolidColorBrush(Color.FromArgb(245, 26, 26, 26)),
                CornerRadius = new CornerRadius(8),
                Padding = new Thickness(8, 4, 8, 4),
                SnapsToDevicePixels = true
            };
            var sp = new StackPanel { Orientation = Orientation.Horizontal };

            _blackoutButton = new ToggleButton { Content = MakeBtnContent("💡", "关灯") };
            StyleToolButton(_blackoutButton);
            _blackoutButton.Checked += (s, e) => SetBlackout(true);
            _blackoutButton.Unchecked += (s, e) => SetBlackout(false);

            var closeBtn = new System.Windows.Controls.Button { Content = MakeBtnContent("✕", NotificationStrings.AnimationOff) };
            StyleToolButton(closeBtn);
            closeBtn.Click += (s, e) => Close();

            sp.Children.Add(_blackoutButton);
            sp.Children.Add(closeBtn);
            bar.Child = sp;
            return bar;
        }

        private static FrameworkElement MakeBtnContent(string icon, string text)
        {
            var sp = new StackPanel { Orientation = Orientation.Vertical, HorizontalAlignment = HorizontalAlignment.Center };
            sp.Children.Add(new TextBlock { Text = icon, FontSize = 16, Foreground = Brushes.White, HorizontalAlignment = HorizontalAlignment.Center });
            sp.Children.Add(new TextBlock { Text = text, FontSize = 11, Foreground = Brushes.White, HorizontalAlignment = HorizontalAlignment.Center, Margin = new Thickness(0, 1, 0, 0) });
            return sp;
        }

        private static void StyleToolButton(ButtonBase b)
        {
            b.Width = 56;
            b.Height = 46;
            b.Margin = new Thickness(3, 0, 3, 0);
            b.Background = Brushes.Transparent;
            b.BorderThickness = new Thickness(0);
            b.Foreground = Brushes.White;
            b.Cursor = Cursors.Hand;
            b.Padding = new Thickness(0);
            b.Template = BuildToolButtonTemplate();
        }

        private static ControlTemplate BuildToolButtonTemplate()
        {
            var t = new ControlTemplate(typeof(ButtonBase));
            var border = new FrameworkElementFactory(typeof(System.Windows.Controls.Border));
            border.Name = "Bd";
            border.SetValue(System.Windows.Controls.Border.BackgroundProperty, new TemplateBindingExtension(System.Windows.Controls.Control.BackgroundProperty));
            border.SetValue(System.Windows.Controls.Border.CornerRadiusProperty, new CornerRadius(6));
            var cp = new FrameworkElementFactory(typeof(ContentPresenter));
            cp.SetValue(ContentPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center);
            cp.SetValue(ContentPresenter.VerticalAlignmentProperty, VerticalAlignment.Center);
            border.AppendChild(cp);
            t.VisualTree = border;

            var hover = new Trigger { Property = UIElement.IsMouseOverProperty, Value = true };
            hover.Setters.Add(new Setter(System.Windows.Controls.Border.BackgroundProperty, new SolidColorBrush(Color.FromArgb(60, 255, 255, 255)), "Bd"));
            t.Triggers.Add(hover);

            var checkedT = new Trigger { Property = ToggleButton.IsCheckedProperty, Value = true };
            checkedT.Setters.Add(new Setter(System.Windows.Controls.Border.BackgroundProperty, new SolidColorBrush(Color.FromRgb(0x05, 0x96, 0x69)), "Bd"));
            t.Triggers.Add(checkedT);
            return t;
        }

        #region 布局

        private void LayoutAll()
        {
            double w = _canvas.ActualWidth;
            double h = _canvas.ActualHeight;
            if (w <= 0 || h <= 0) return;

            // 首次居中
            if (_boxLeft + _boxWidth > w) _boxLeft = Math.Max(0, w - _boxWidth);
            if (_boxTop + _boxHeight > h) _boxTop = Math.Max(0, h - _boxHeight);

            // 遮罩占满
            _overlay.Width = w;
            _overlay.Height = h;
            System.Windows.Controls.Canvas.SetLeft(_overlay, 0);
            System.Windows.Controls.Canvas.SetTop(_overlay, 0);
            UpdateOverlayClip();

            // 选择框
            _selectionBorder.Width = _boxWidth;
            _selectionBorder.Height = _boxHeight;
            System.Windows.Controls.Canvas.SetLeft(_selectionBorder, _boxLeft);
            System.Windows.Controls.Canvas.SetTop(_selectionBorder, _boxTop);

            // 8 个控点（中心定位）
            PositionHandle(0, _boxLeft, _boxTop);                              // NW
            PositionHandle(1, _boxLeft + _boxWidth / 2, _boxTop);              // N
            PositionHandle(2, _boxLeft + _boxWidth, _boxTop);                  // NE
            PositionHandle(3, _boxLeft + _boxWidth, _boxTop + _boxHeight / 2); // E
            PositionHandle(4, _boxLeft + _boxWidth, _boxTop + _boxHeight);    // SE
            PositionHandle(5, _boxLeft + _boxWidth / 2, _boxTop + _boxHeight); // S
            PositionHandle(6, _boxLeft, _boxTop + _boxHeight);                 // SW
            PositionHandle(7, _boxLeft, _boxTop + _boxHeight / 2);             // W

            // 工具栏：选择框正下方居中；若超出则放上方
            _toolbar.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
            double tw = _toolbar.DesiredSize.Width, th = _toolbar.DesiredSize.Height;
            double tx = _boxLeft + _boxWidth / 2 - tw / 2;
            double ty = _boxTop + _boxHeight + 12;
            if (ty + th > h) ty = _boxTop - th - 12;
            tx = Math.Max(8, Math.Min(w - tw - 8, tx));
            System.Windows.Controls.Canvas.SetLeft(_toolbar, tx);
            System.Windows.Controls.Canvas.SetTop(_toolbar, ty);
        }

        private void PositionHandle(int i, double cx, double cy)
        {
            var dot = _handles[i];
            System.Windows.Controls.Canvas.SetLeft(dot, cx - dot.Width / 2);
            System.Windows.Controls.Canvas.SetTop(dot, cy - dot.Height / 2);
        }

        private void UpdateOverlayClip()
        {
            // 用 EvenOdd Geometry 在 overlay 上挖空选择框区域
            double w = _canvas.ActualWidth;
            double h = _canvas.ActualHeight;
            if (w <= 0 || h <= 0) { _overlay.Clip = null; return; }

            var outer = new RectangleGeometry(new Rect(0, 0, w, h));
            var inner = new RectangleGeometry(new Rect(_boxLeft, _boxTop, _boxWidth, _boxHeight));
            var combined = new CombinedGeometry(GeometryCombineMode.Exclude, outer, inner);
            _overlay.Clip = combined;
        }

        #endregion

        #region 拖动

        private bool _draggingBox;
        private Point _dragStart;
        private double _dragBoxLeft, _dragBoxTop;

        private void SelectionBorder_MouseDown(object sender, MouseButtonEventArgs e)
        {
            _draggingBox = true;
            _dragStart = e.GetPosition(_canvas);
            _dragBoxLeft = _boxLeft;
            _dragBoxTop = _boxTop;
            _selectionBorder.CaptureMouse();
            e.Handled = true;
        }

        private void SelectionBorder_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_draggingBox) return;
            var p = e.GetPosition(_canvas);
            _boxLeft = Math.Max(0, Math.Min(_canvas.ActualWidth - _boxWidth, _dragBoxLeft + p.X - _dragStart.X));
            _boxTop = Math.Max(0, Math.Min(_canvas.ActualHeight - _boxHeight, _dragBoxTop + p.Y - _dragStart.Y));
            LayoutAll();
        }

        private void SelectionBorder_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (!_draggingBox) return;
            _draggingBox = false;
            _selectionBorder.ReleaseMouseCapture();
        }

        #endregion

        #region 缩放

        private bool _resizing;
        private string _resizeTag;
        private Point _resizeStart;
        private double _rL, _rT, _rW, _rH;

        private void Handle_MouseDown(object sender, MouseButtonEventArgs e)
        {
            var el = (FrameworkElement)sender;
            _resizing = true;
            _resizeTag = (string)el.Tag;
            _resizeStart = e.GetPosition(_canvas);
            _rL = _boxLeft; _rT = _boxTop; _rW = _boxWidth; _rH = _boxHeight;
            el.CaptureMouse();
            e.Handled = true;
        }

        private void Handle_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_resizing) return;
            var p = e.GetPosition(_canvas);
            double dx = p.X - _resizeStart.X;
            double dy = p.Y - _resizeStart.Y;

            double nL = _rL, nT = _rT, nW = _rW, nH = _rH;
            switch (_resizeTag)
            {
                case "NW": nL = _rL + dx; nT = _rT + dy; nW = _rW - dx; nH = _rH - dy; break;
                case "N": nT = _rT + dy; nH = _rH - dy; break;
                case "NE": nT = _rT + dy; nW = _rW + dx; nH = _rH - dy; break;
                case "E": nW = _rW + dx; break;
                case "SE": nW = _rW + dx; nH = _rH + dy; break;
                case "S": nH = _rH + dy; break;
                case "SW": nL = _rL + dx; nW = _rW - dx; nH = _rH + dy; break;
                case "W": nL = _rL + dx; nW = _rW - dx; break;
            }
            if (nW < MinBoxW) { if (_resizeTag.Contains("W")) nL -= MinBoxW - nW; nW = MinBoxW; }
            if (nH < MinBoxH) { if (_resizeTag.Contains("N")) nT -= MinBoxH - nH; nH = MinBoxH; }

            // 限制在窗口内
            nL = Math.Max(0, nL);
            nT = Math.Max(0, nT);
            if (nL + nW > _canvas.ActualWidth) nW = _canvas.ActualWidth - nL;
            if (nT + nH > _canvas.ActualHeight) nH = _canvas.ActualHeight - nT;

            _boxLeft = nL; _boxTop = nT; _boxWidth = nW; _boxHeight = nH;
            LayoutAll();
        }

        private void Handle_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (!_resizing) return;
            _resizing = false;
            ((FrameworkElement)sender).ReleaseMouseCapture();
        }

        #endregion

        #region 关灯

        private void SetBlackout(bool on)
        {
            _blackoutOn = on;
            _overlay.Fill = new SolidColorBrush(on
                ? Color.FromArgb(245, 0, 0, 0)
                : Color.FromArgb(102, 0, 0, 0));
        }

        #endregion

        #region Magnifier 子窗口

        private class MagnifierHost : HwndHost
        {
            private readonly MagnifierWindow _owner;
            public IntPtr MagHwnd { get; private set; }
            public MagnifierHost(MagnifierWindow owner) { _owner = owner; }

            protected unsafe override HandleRef BuildWindowCore(HandleRef hwndParent)
            {
                if (!PInvoke.MagInitialize()) throw new InvalidOperationException("MagInitialize 失败");
                _owner._magInitialized = true;

                MagHwnd = PInvoke.CreateWindowEx(
                    0, MagnifierClassName, "ICCMagnifier",
                    WINDOW_STYLE.WS_CHILD | WINDOW_STYLE.WS_VISIBLE,
                    0, 0, 100, 100,
                    new HWND(hwndParent.Handle), null, null, null);
                _owner._magHwnd = MagHwnd;
                return new HandleRef(this, MagHwnd);
            }

            protected override void DestroyWindowCore(HandleRef hwnd)
            {
                if (hwnd.Handle != IntPtr.Zero) PInvoke.DestroyWindow(new HWND(hwnd.Handle));
                MagHwnd = IntPtr.Zero;
            }
        }

        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            _hwndSource = (HwndSource)PresentationSource.FromVisual(this);
            ApplyTransform();
            if (_hwndSource != null && _magHwnd != IntPtr.Zero)
            {
                HWND pHandle = new HWND(_hwndSource.Handle);
                PInvoke.MagSetWindowFilterList(new HWND(_magHwnd), MW_FILTERMODE.MW_FILTERMODE_EXCLUDE, 1, ref pHandle);
            }


            _timer = new DispatcherTimer(DispatcherPriority.Render) { Interval = TimeSpan.FromMilliseconds(33) };
            _timer.Tick += OnTick;
            _timer.Start();
        }

        private unsafe void ApplyTransform()
        {
            if (_magHwnd == IntPtr.Zero) return;
            var m = new MAGTRANSFORM();

            m.v[0] = _zoom;
            m.v[1] = 0f;
            m.v[2] = 0f;
            m.v[3] = 0f;
            m.v[4] = _zoom;
            m.v[5] = 0f;
            m.v[6] = 0f;
            m.v[7] = 0f;
            m.v[8] = 1.0f;
            PInvoke.MagSetWindowTransform(new HWND(_magHwnd), ref m);
        }

        private void OnTick(object sender, EventArgs e)
        {
            if (_magHwnd == IntPtr.Zero || _magHost == null) return;
            if (_magHost.RenderSize.Width <= 0) return;

            // 选择框在屏幕物理像素坐标
            var hostOffset = _magHost.TransformToAncestor(this).Transform(new Point(0, 0));
            var tl = PointToScreen(hostOffset);
            var br = PointToScreen(new Point(hostOffset.X + _magHost.RenderSize.Width,
                                             hostOffset.Y + _magHost.RenderSize.Height));
            int viewW = (int)(br.X - tl.X);
            int viewH = (int)(br.Y - tl.Y);
            if (viewW <= 0 || viewH <= 0) return;

            int srcW = Math.Max(1, (int)(viewW / _zoom));
            int srcH = Math.Max(1, (int)(viewH / _zoom));
            int cx = (int)((tl.X + br.X) / 2);
            int cy = (int)((tl.Y + br.Y) / 2);
            var src = new RECT(cx - srcW / 2, cy - srcH / 2,
                               cx - srcW / 2 + srcW, cy - srcH / 2 + srcH);
            PInvoke.MagSetWindowSource(new HWND(_magHwnd), src);
            unsafe { PInvoke.InvalidateRect(new HWND(_magHwnd), (RECT*)IntPtr.Zero.ToPointer(), false); }
        }

        #endregion

        protected override void OnClosed(EventArgs e)
        {
            if (_timer != null) { _timer.Stop(); _timer.Tick -= OnTick; _timer = null; }
            if (_magInitialized) { PInvoke.MagUninitialize(); _magInitialized = false; }
            base.OnClosed(e);
        }
    }
}