using MainShell.EventArgsFolder;
using MainShell.Log;
using MainShell.Vision;
using MwFramework.Device.Model;
using MwFramework.Controls.ControlCanvas.DrawingControl;
using Stylet;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using AppCameraType = MainShell.Common.CameraType;
using System.Windows.Media;

namespace MainShell.Common.Display.ViewModel
{
    public class CameraViewModel : Screen, IHandle<DisplayImageEventArgs>, IHandle<DisplayFindTemplateResultEventArgs>
    {
        private readonly IEventAggregator _eventAggregator;
        public AppCameraType CameraType { get; }

        private WriteableBitmap currentImage;
        private WriteableBitmap _displayImage;
        public WriteableBitmap DisplayImage
        {
            get { return _displayImage; }
            set
            {
                SetAndNotify(ref _displayImage, value);
            }
        }

        private ObservableCollection<object> _shapes = new ObservableCollection<object>();
        public ObservableCollection<object> Shapes
        {
            get { return _shapes; }
            set
            {
                if (_shapes != value) { _shapes = value; OnPropertyChanged(nameof(Shapes)); }
            }
        }
        /// <summary>
        /// 根据 CameraData 更新并返回 WriteableBitmap。
        /// 优化要点：
        /// - 重用已有 WriteableBitmap（当尺寸与像素格式相同时）以减少分配。
        /// - 校验参数与缓冲区长度。
        /// - 捕获并记录异常，失败时返回 null（不抛出）。
        /// </summary>
        public WriteableBitmap UpdateBitmap(CameraData cameraData)
        {
            if (cameraData == null)
            {
                "图片数据为空".LogSysError();
                return null;
            }

            try
            {
                int width = (int)cameraData.Width;
                int height = (int)cameraData.Height;
                int bitCnt = cameraData.Bit;
                byte[] buffer = cameraData.BufferData;

                if (width <= 0 || height <= 0)
                {
                    $"CameraViewModel.UpdateBitmap: invalid size {width}x{height}".LogSysError();
                    return null;
                }

                // 选择像素格式
                System.Windows.Media.PixelFormat pixelFormat = bitCnt == 1
                    ? System.Windows.Media.PixelFormats.Gray8
                    : (bitCnt == 3 ? System.Windows.Media.PixelFormats.Bgr24 : System.Windows.Media.PixelFormats.Bgra32);

                // 计算每行字节数（stride）
                int bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
                int stride = width * bytesPerPixel;
                long requiredLength = (long)stride * height;

                if (buffer == null)
                {
                    "CameraViewModel.UpdateBitmap: buffer is null".LogSysError();
                    return null;
                }

                if (buffer.Length < requiredLength)
                {
                    ($"CameraViewModel.UpdateBitmap: buffer length {buffer.Length} is less than required {requiredLength}").LogSysError();
                    return null;
                }

                // 如果现有 bitmap 可复用（尺寸和格式一致），就重用以减少 GC/分配
                if (currentImage == null ||
                    currentImage.PixelWidth != width ||
                    currentImage.PixelHeight != height ||
                    !currentImage.Format.Equals(pixelFormat))
                {
                    // 新建 WriteableBitmap
                    currentImage = new WriteableBitmap(width, height, 96, 96, pixelFormat, null);
                }

                // 将字节拷贝到 BackBuffer（UI 线程中调用）
                currentImage.Lock();
                try
                {
                    // BackBuffer 为 IntPtr，使用 Marshal.Copy 从 byte[] 拷贝
                    System.Runtime.InteropServices.Marshal.Copy(buffer, 0, currentImage.BackBuffer, (int)requiredLength);
                    currentImage.AddDirtyRect(new Int32Rect(0, 0, width, height));
                }
                finally
                {
                    currentImage.Unlock();
                }

                return currentImage;
            }
            catch (Exception ex)
            {
                ($"CameraViewModel.UpdateBitmap exception: {ex}").LogSysError();
                return null;
            }
        }

        public CameraViewModel(IEventAggregator eventAggregator, AppCameraType cameraType)
        {
            _eventAggregator = eventAggregator;
            CameraType = cameraType;
            _eventAggregator?.Subscribe(this);
        }

        public void Handle(DisplayImageEventArgs message)
        {
            if (message == null || message.CameraType != CameraType)
            {
                return;
            }

            CommonUti.RunOnUi(() =>
            {
                WriteableBitmap bmp = UpdateBitmap(message.CameraData);
                // 只有在成功生成 bitmap 时才更新 DisplayImage，避免把 null 赋值导致 UI 清空
                if (bmp != null)
                {
                    DisplayImage = bmp;
                }
            });
        }

        public void Handle(DisplayFindTemplateResultEventArgs message)
        {
            if (message == null || message.CameraType != CameraType)
            {
                return;
            }
            CommonUti.RunOnUi(() =>
            {
                ApplyTemplateResultShapes(message);
            });
        }

        private void ApplyTemplateResultShapes(DisplayFindTemplateResultEventArgs message)
        {
            if (message.ClearShapesBeforeDisplay)
            {
                Shapes.Clear();
            }

            if (message.Result == null)
            {
                return;
            }

            AppendCenterShapes(message.Result);
            AppendContourShape(message.Result.Contour);
            AppendCircleShapes(message.Result.Circles);
            AppendLineShapes(message.Result.Lines);
            AppendRectangleShapes(message.Result.Rectangles);
        }

        private void AppendCenterShapes(FindTemplateResult result)
        {
            if (result == null || !AreFinite(result.CenterX, result.CenterY, result.Score))
            {
                return;
            }
            
            ShapeDrawing pointShape = new ShapeDrawing();
            pointShape.X = result.CenterX;
            pointShape.Y = result.CenterY;
            Shapes.Add(pointShape);

            TextShapeDrawing textShape = new TextShapeDrawing();
            textShape.X = result.CenterX;
            textShape.Y = result.CenterY;
            textShape.Text = $"Score:{result.Score:F3}";
            Shapes.Add(textShape);
        }

        private void AppendContourShape(FindTemplateContourResult contour)
        {
            if (contour == null || !AreFinite(contour.StartX, contour.StartY, contour.EndX, contour.EndY))
            {
                return;
            }

            RectShapeDrawing contourShape = new RectShapeDrawing();
            contourShape.X = contour.StartX;
            contourShape.Y = contour.StartY;
            contourShape.X1 = contour.EndX;
            contourShape.Y1 = contour.EndY;
            Shapes.Add(contourShape);
        }

        private void AppendCircleShapes(IList<FindTemplateCircleResult> circles)
        {
            if (circles == null)
            {
                return;
            }

            foreach (FindTemplateCircleResult circle in circles)
            {
                if (circle == null || !AreFinite(circle.CenterX, circle.CenterY, circle.Radius))
                {
                    continue;
                }

                CircleShapeDrawing circleShape = new CircleShapeDrawing();
                circleShape.X = circle.CenterX;
                circleShape.Y = circle.CenterY;
                circleShape.CenterPoint = new Point(circle.CenterX, circle.CenterY);
                circleShape.RadiusX = circle.Radius;
                circleShape.RadiusY = circle.Radius;
                circleShape.LineWidth = 1;
                circleShape.FillColor = Brushes.Blue;
                Shapes.Add(circleShape);
            }
        }

        private void AppendLineShapes(IList<FindTemplateLineResult> lines)
        {
            if (lines == null)
            {
                return;
            }

            foreach (FindTemplateLineResult line in lines)
            {
                if (line == null || !AreFinite(line.StartX, line.StartY, line.EndX, line.EndY))
                {
                    continue;
                }

                LineShapeDrawing lineShape = new LineShapeDrawing();
                lineShape.X = line.StartX;
                lineShape.Y = line.StartY;
                lineShape.X1 = line.EndX;
                lineShape.Y1 = line.EndY;
                Shapes.Add(lineShape);
            }
        }

        private void AppendRectangleShapes(IList<FindTemplateRectangleResult> rectangles)
        {
            if (rectangles == null)
            {
                return;
            }

            foreach (FindTemplateRectangleResult rectangle in rectangles)
            {
                if (rectangle == null || !AreFinite(rectangle.StartX, rectangle.StartY, rectangle.Width, rectangle.Height, rectangle.Angle))
                {
                    continue;
                }

                double halfWidth = rectangle.Width / 2d;
                double halfHeight = rectangle.Height / 2d;
                double cosAngle = Math.Cos(rectangle.Angle);
                double sinAngle = Math.Sin(rectangle.Angle);
                double centerX = rectangle.StartX + (halfWidth * cosAngle) - (halfHeight * sinAngle);
                double centerY = rectangle.StartY + (halfWidth * sinAngle) + (halfHeight * cosAngle);

                RectShape2Drawing rectangleShape = new RectShape2Drawing();
                rectangleShape.X = centerX;
                rectangleShape.Y = centerY;
                rectangleShape.CenterX = centerX;
                rectangleShape.CenterY = centerY;
                rectangleShape.HalfWidth = halfWidth;
                rectangleShape.HalfHeigth = halfHeight;
                rectangleShape.Angle = rectangle.Angle;
                Shapes.Add(rectangleShape);
            }
        }

        private static bool AreFinite(params double[] values)
        {
            if (values == null)
            {
                return false;
            }

            foreach (double value in values)
            {
                if (double.IsNaN(value) || double.IsInfinity(value))
                {
                    return false;
                }
            }

            return true;
        }
    }
}
