using MainShell.Common;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.ComponentModel;

namespace MainShell.Resources.CustomControl
{
    /// <summary>
    /// 高性能芯片Map图控件，支持5-10万个点的动态状态更新，支持鼠标拖拽和缩放
    /// </summary>
    public class DieMapControl : FrameworkElement
    {
        private int _rows;
        private int _columns;
        private DieState[,] _dieStates;
        private Point[,] _dieCoordinates;
        private double _minX, _maxX, _minY, _maxY;
        private Dictionary<DieState, Brush> _stateBrushes;

        // 渲染相关
        private DrawingVisual _visual;
        private VisualCollection _visuals;
        private DispatcherTimer _renderTimer;
        private bool _needsRedraw = false;

        // 交互相关
        private MatrixTransform _transform = new MatrixTransform();
        private Point _lastMousePosition;
        private Point _mouseDownPosition;
        private bool _isDragging;
        private bool _isViewChangedByUser;
        private Popup _infoPopup;
        private TextBlock _infoText;

        public static readonly DependencyProperty BackgroundProperty =
            DependencyProperty.Register("Background", typeof(Brush), typeof(DieMapControl), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender));

        public Brush Background
        {
            get { return (Brush)GetValue(BackgroundProperty); }
            set { SetValue(BackgroundProperty, value); }
        }

        public static readonly DependencyProperty MapModelProperty =
            DependencyProperty.Register("MapModel", typeof(DieMapModel), typeof(DieMapControl), new PropertyMetadata(null, OnMapModelChanged));

        public DieMapModel MapModel
        {
            get { return (DieMapModel)GetValue(MapModelProperty); }
            set { SetValue(MapModelProperty, value); }
        }

        public static readonly DependencyProperty DieClickedCommandProperty =
            DependencyProperty.Register("DieClickedCommand", typeof(ICommand), typeof(DieMapControl), new PropertyMetadata(null));

        public ICommand DieClickedCommand
        {
            get { return (ICommand)GetValue(DieClickedCommandProperty); }
            set { SetValue(DieClickedCommandProperty, value); }
        }

        public event EventHandler<DieClickedEventArgs> DieClicked;

        public class DieClickedEventArgs : EventArgs
        {
            public int Row { get; }
            public int Col { get; }
            public DieState State { get; }

            public DieClickedEventArgs(int row, int col, DieState state)
            {
                Row = row;
                Col = col;
                State = state;
            }
        }

        private static void OnMapModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (DieMapControl)d;
            if (e.OldValue is DieMapModel oldModel)
            {
                oldModel.MapInitialized -= control.OnMapInitialized;
                oldModel.DieStateChanged -= control.OnDieStateChanged;
                oldModel.DieStatesChanged -= control.OnDieStatesChanged;
            }
            if (e.NewValue is DieMapModel newModel)
            {
                newModel.MapInitialized += control.OnMapInitialized;
                newModel.DieStateChanged += control.OnDieStateChanged;
                newModel.DieStatesChanged += control.OnDieStatesChanged;
                control.InitializeFromModel(newModel);
            }
        }

        private void OnMapInitialized(object sender, EventArgs e)
        {
            InitializeFromModel(MapModel);
        }

        private void OnDieStateChanged(object sender, (int Row, int Col, DieState State) e)
        {
            _needsRedraw = true;
        }

        private void OnDieStatesChanged(object sender, IEnumerable<(int Row, int Col, DieState State)> e)
        {
            _needsRedraw = true;
        }

        public static readonly DependencyProperty DieSizeProperty =
            DependencyProperty.Register("DieSize", typeof(double), typeof(DieMapControl), new FrameworkPropertyMetadata(4.0, FrameworkPropertyMetadataOptions.AffectsRender, OnSizeChanged));

        public double DieSize
        {
            get { return (double)GetValue(DieSizeProperty); }
            set { SetValue(DieSizeProperty, value); }
        }

        public static readonly DependencyProperty SpacingProperty =
            DependencyProperty.Register("Spacing", typeof(double), typeof(DieMapControl), new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsRender, OnSizeChanged));

        public double Spacing
        {
            get { return (double)GetValue(SpacingProperty); }
            set { SetValue(SpacingProperty, value); }
        }

        private static void OnSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (DieMapControl)d;
            control.RedrawAll();
        }

        public DieMapControl()
        {
            _visuals = new VisualCollection(this);
            _visual = new DrawingVisual();
            _visuals.Add(_visual);

            // 初始化画刷字典，冻结以提高性能
            _stateBrushes = new Dictionary<DieState, Brush>
            {
                { DieState.Available, CreateFrozenBrush(Color.FromRgb(211, 211, 211)) }, // 浅灰色
                { DieState.Used, CreateFrozenBrush(Color.FromRgb(50, 205, 50)) },     // 绿色
                { DieState.Error, CreateFrozenBrush(Color.FromRgb(255, 0, 0)) },           // 红色
                { DieState.NotExist, Brushes.Transparent },                                    // 透明
                { DieState.Current, CreateFrozenBrush(Color.FromRgb(0, 191, 255)) },       // 深天蓝 - 当前位置
                { DieState.Target, CreateFrozenBrush(Color.FromRgb(255, 165, 0)) }         // 橙色 - 目标位置
            };

            // 初始化Popup
            _infoPopup = new Popup
            {
                Placement = PlacementMode.Mouse,
                StaysOpen = false,
                AllowsTransparency = true
            };
            Border popupBorder = new Border
            {
                Background = new SolidColorBrush(Color.FromArgb(220, 30, 30, 30)),
                BorderBrush = Brushes.Gray,
                BorderThickness = new Thickness(1),
                CornerRadius = new CornerRadius(4),
                Padding = new Thickness(8)
            };
            _infoText = new TextBlock
            {
                Foreground = Brushes.White,
                FontSize = 12
            };
            popupBorder.Child = _infoText;
            _infoPopup.Child = popupBorder;

            // 鼠标事件
            this.MouseWheel += OnMouseWheel;
            this.MouseDown += OnMouseDown;
            this.MouseUp += OnMouseUp;
            this.MouseMove += OnMouseMove;
            this.MouseLeave += OnMouseLeave;

            // 裁剪超出边界的内容
            this.ClipToBounds = true;

            // 初始化定时器，1秒3次 (约333ms)
            _renderTimer = new DispatcherTimer(DispatcherPriority.Render);
            _renderTimer.Interval = TimeSpan.FromMilliseconds(333);
            _renderTimer.Tick += RenderTimer_Tick;
            _renderTimer.Start();
        }

        private void RenderTimer_Tick(object sender, EventArgs e)
        {
            if (_needsRedraw)
            {
                RedrawAll();
                _needsRedraw = false;
            }
        }

        private SolidColorBrush CreateFrozenBrush(Color color)
        {
            var brush = new SolidColorBrush(color);
            brush.Freeze();
            return brush;
        }

        protected override int VisualChildrenCount => _visuals.Count;

        protected override Visual GetVisualChild(int index)
        {
            if (index < 0 || index >= _visuals.Count)
                throw new ArgumentOutOfRangeException();
            return _visuals[index];
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            if (Background != null)
            {
                drawingContext.DrawRectangle(Background, null, new Rect(0, 0, ActualWidth, ActualHeight));
            }
        }

        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);
            if (!_isViewChangedByUser && _rows > 0)
            {
                FitToScreen();
            }
        }

        private void InitializeFromModel(DieMapModel model)
        {
            if (model == null) return;

            _rows = model.Rows;
            _columns = model.Columns;
            _dieStates = model.States;
            _dieCoordinates = model.Coordinates;

            if (_dieCoordinates != null)
            {
                CalculateBounds();
            }

            // 重置变换
            _transform.Matrix = Matrix.Identity;

            // 延迟执行FitToScreen，确保控件已经布局完成
            Dispatcher.BeginInvoke(new Action(() =>
            {
                if (ActualWidth > 0 && ActualHeight > 0)
                {
                    FitToScreen();
                }
                else
                {
                    RedrawAll();
                }
            }), DispatcherPriority.Loaded);
        }

        private void CalculateBounds()
        {
            _minX = double.MaxValue;
            _maxX = double.MinValue;
            _minY = double.MaxValue;
            _maxY = double.MinValue;

            for (int r = 0; r < _rows; r++)
            {
                for (int c = 0; c < _columns; c++)
                {
                    var pt = _dieCoordinates[r, c];
                    if (pt.X < _minX) _minX = pt.X;
                    if (pt.X > _maxX) _maxX = pt.X;
                    if (pt.Y < _minY) _minY = pt.Y;
                    if (pt.Y > _maxY) _maxY = pt.Y;
                }
            }
        }

        private void RedrawAll()
        {
            if (_rows == 0 || _columns == 0 || _dieStates == null) return;

            using (DrawingContext dc = _visual.RenderOpen())
            {
                // 应用当前的缩放和平移变换
                dc.PushTransform(_transform);

                double size = DieSize;
                double spacing = Spacing;

                double physicalWidth = _maxX - _minX;
                double physicalHeight = _maxY - _minY;

                if (physicalWidth == 0) physicalWidth = 1;
                if (physicalHeight == 0) physicalHeight = 1;

                // 基础绘制区域大小（未缩放前）
                double baseWidth = _columns * (size + spacing);
                double baseHeight = _rows * (size + spacing);

                for (int r = 0; r < _rows; r++)
                {
                    for (int c = 0; c < _columns; c++)
                    {
                        DieState state = _dieStates[r, c];
                        if (state == DieState.NotExist) continue;

                        Brush brush = _stateBrushes.ContainsKey(state) ? _stateBrushes[state] : Brushes.Transparent;
                        if (brush == Brushes.Transparent) continue;

                        double x, y;

                        if (_dieCoordinates != null)
                        {
                            var pt = _dieCoordinates[r, c];
                            x = ((pt.X - _minX) / physicalWidth) * baseWidth;
                            y = (1.0 - (pt.Y - _minY) / physicalHeight) * baseHeight;
                        }
                        else
                        {
                            x = c * (size + spacing);
                            y = r * (size + spacing);
                        }

                        dc.DrawRectangle(brush, null, new Rect(x, y, size, size));
                    }
                }

                dc.Pop();
            }

            _needsRedraw = false;
        }

        #region 鼠标交互 (缩放与平移)

        private void OnMouseWheel(object sender, MouseWheelEventArgs e)
        {
            Point mousePos = e.GetPosition(this);
            double scaleFactor = e.Delta > 0 ? 1.1 : 1 / 1.1;

            Matrix matrix = _transform.Matrix;
            matrix.ScaleAt(scaleFactor, scaleFactor, mousePos.X, mousePos.Y);
            _transform.Matrix = matrix;
            _isViewChangedByUser = true;

            RedrawAll();
            e.Handled = true;
        }

        private void OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Middle)
            {
                FitToScreen();
            }
            else if (e.ChangedButton == MouseButton.Left)
            {
                _mouseDownPosition = e.GetPosition(this);
                _lastMousePosition = _mouseDownPosition;
                _isDragging = true;
                this.CaptureMouse();
                _infoPopup.IsOpen = false;
            }
        }

        private void OnMouseUp(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Left)
            {
                _isDragging = false;
                this.ReleaseMouseCapture();

                Point currentPosition = e.GetPosition(this);
                if ((currentPosition - _mouseDownPosition).Length < 5)
                {
                    if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                    {
                        ShowDieInfo(currentPosition);
                    }
                    else
                    {
                        HandleDieClick(currentPosition);
                    }
                }
            }
        }

        private void HandleDieClick(Point mousePos)
        {
            if (_rows == 0 || _columns == 0 || _dieStates == null) return;

            if (!_transform.Matrix.HasInverse) return;
            Matrix inverse = _transform.Matrix;
            inverse.Invert();
            Point canvasPos = inverse.Transform(mousePos);

            double size = DieSize;
            double spacing = Spacing;
            double physicalWidth = _maxX - _minX;
            double physicalHeight = _maxY - _minY;
            if (physicalWidth == 0) physicalWidth = 1;
            if (physicalHeight == 0) physicalHeight = 1;

            double baseWidth = _columns * (size + spacing);
            double baseHeight = _rows * (size + spacing);

            int clickedRow = -1;
            int clickedCol = -1;

            for (int r = 0; r < _rows; r++)
            {
                for (int c = 0; c < _columns; c++)
                {
                    DieState state = _dieStates[r, c];
                    if (state == DieState.NotExist) continue;

                    double x, y;
                    if (_dieCoordinates != null)
                    {
                        var pt = _dieCoordinates[r, c];
                        x = ((pt.X - _minX) / physicalWidth) * baseWidth;
                        y = (1.0 - (pt.Y - _minY) / physicalHeight) * baseHeight;
                    }
                    else
                    {
                        x = c * (size + spacing);
                        y = r * (size + spacing);
                    }

                    if (canvasPos.X >= x && canvasPos.X <= x + size &&
                        canvasPos.Y >= y && canvasPos.Y <= y + size)
                    {
                        clickedRow = r;
                        clickedCol = c;
                        break;
                    }
                }
                if (clickedRow != -1) break;
            }

            if (clickedRow != -1)
            {
                var dieInfo = (Row: clickedRow, Col: clickedCol, State: _dieStates[clickedRow, clickedCol]);

                // 触发事件
                DieClicked?.Invoke(this, new DieClickedEventArgs(clickedRow, clickedCol, _dieStates[clickedRow, clickedCol]));

                // 触发命令
                if (DieClickedCommand != null && DieClickedCommand.CanExecute(dieInfo))
                {
                    DieClickedCommand.Execute(dieInfo);
                }
            }
        }

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (_isDragging)
            {
                Point currentPosition = e.GetPosition(this);
                Vector delta = currentPosition - _lastMousePosition;

                Matrix matrix = _transform.Matrix;
                matrix.Translate(delta.X, delta.Y);
                _transform.Matrix = matrix;
                _isViewChangedByUser = true;

                _lastMousePosition = currentPosition;
                RedrawAll();
            }
        }

        private void OnMouseLeave(object sender, MouseEventArgs e)
        {
            if (_isDragging)
            {
                _isDragging = false;
                this.ReleaseMouseCapture();
            }
        }

        private void FitToScreen()
        {
            if (_rows == 0 || _columns == 0) return;

            double size = DieSize;
            double spacing = Spacing;
            double baseWidth = _columns * (size + spacing);
            double baseHeight = _rows * (size + spacing);

            if (baseWidth == 0 || baseHeight == 0 || ActualWidth == 0 || ActualHeight == 0) return;

            double scaleX = ActualWidth / baseWidth;
            double scaleY = ActualHeight / baseHeight;
            double scale = Math.Min(scaleX, scaleY) * 0.9; // 90% to leave some margin

            if (scale <= 0) scale = 1;

            _transform.Matrix = new Matrix(scale, 0, 0, scale, 
                (ActualWidth - baseWidth * scale) / 2, 
                (ActualHeight - baseHeight * scale) / 2);
            _isViewChangedByUser = false;

            RedrawAll();
        }

        private void ShowDieInfo(Point mousePos)
        {
            if (_rows == 0 || _columns == 0 || _dieStates == null) return;

            if (!_transform.Matrix.HasInverse) return;
            Matrix inverse = _transform.Matrix;
            inverse.Invert();
            Point canvasPos = inverse.Transform(mousePos);

            double size = DieSize;
            double spacing = Spacing;
            double physicalWidth = _maxX - _minX;
            double physicalHeight = _maxY - _minY;
            if (physicalWidth == 0) physicalWidth = 1;
            if (physicalHeight == 0) physicalHeight = 1;

            double baseWidth = _columns * (size + spacing);
            double baseHeight = _rows * (size + spacing);

            int clickedRow = -1;
            int clickedCol = -1;

            for (int r = 0; r < _rows; r++)
            {
                for (int c = 0; c < _columns; c++)
                {
                    DieState state = _dieStates[r, c];
                    if (state == DieState.NotExist) continue;

                    double x, y;
                    if (_dieCoordinates != null)
                    {
                        var pt = _dieCoordinates[r, c];
                        x = ((pt.X - _minX) / physicalWidth) * baseWidth;
                        y = (1.0 - (pt.Y - _minY) / physicalHeight) * baseHeight;
                    }
                    else
                    {
                        x = c * (size + spacing);
                        y = r * (size + spacing);
                    }

                    if (canvasPos.X >= x && canvasPos.X <= x + size &&
                        canvasPos.Y >= y && canvasPos.Y <= y + size)
                    {
                        clickedRow = r;
                        clickedCol = c;
                        break;
                    }
                }
                if (clickedRow != -1) break;
            }

            if (clickedRow != -1)
            {
                DieState state = _dieStates[clickedRow, clickedCol];
                string info = $"行 (Row): {clickedRow}\n列 (Col): {clickedCol}\n状态: {MainShell.Converter.EnumHelper.GetEnumDescription(state)}";
                if (_dieCoordinates != null)
                {
                    var pt = _dieCoordinates[clickedRow, clickedCol];
                    info += $"\nX: {pt.X:F3}\nY: {pt.Y:F3}";
                }

                _infoText.Text = info;
                _infoPopup.IsOpen = true;
            }
            else
            {
                _infoPopup.IsOpen = false;
            }
        }

        #endregion
    }
}