using MainShell.Common;
using MainShell.DeviceMaintance.Model;
using MainShell.Hardware;
using MainShell.Log;
using MainShell.Models;
using MainShell.Motion;
using MainShell.Parameter;
using MaxwellControl.Tools;
using MaxwellFramework.Core.Interfaces;
using MwFramework.ManagerService;
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace MainShell.DeviceMaintance.ViewModel
{
    public class NeedleCameraPrintViewModel : DeviceMaintanceBaseViewModel
    {
        private NeedlePrintCalibrateSetting _needlePrintCalibrateSetting;
        private readonly IParamList _paramList;
        private readonly HardwareManager _device;
        private readonly SafeAxisMotion _safeMotion;
        private readonly GlobalParameterContext _globalParam;
        private CancellationTokenSource _cancellationTokenSource;
        private List<Point> _workPos;
        private readonly double _z1Speed = 70;
        private MaintanceRecord maintanceRecord;

        private ParameterHelper _parameterHelper = new ParameterHelper();
        public ParameterHelper ParameterHelper
        {
            get
            {
                return _parameterHelper;
            }
            set
            {
                _parameterHelper = value;
                OnPropertyChanged(nameof(ParameterHelper));
            }
        }

        private MPoint _cameraPoint;

        public MPoint CameraPoint
        {
            get { return _cameraPoint; }
            set { SetAndNotify(ref _cameraPoint, value); }
        }

        private MPoint _currentNeedlePoint;

        public MPoint CurrentNeedlePoint
        {
            get { return _currentNeedlePoint; }
            set { SetAndNotify(ref _currentNeedlePoint, value); }
        }

        private MPoint _currentNeedleOffsetPoint;

        public MPoint CurrentNeedleOffsetPoint
        {
            get { return _currentNeedleOffsetPoint; }
            set { SetAndNotify(ref _currentNeedleOffsetPoint, value); }
        }


        private NeedlePrintCalibrateParameter _needlePrintCalibrateParameter;

        public NeedlePrintCalibrateParameter NeedlePrintCalibrateParameter
        {
            get { return _needlePrintCalibrateParameter; }
            set { SetAndNotify(ref _needlePrintCalibrateParameter, value); }
        }

        private bool _uiEnable = true;

        public bool UiEnable
        {
            get { return _uiEnable; }
            set
            {
                if (SetAndNotify(ref _uiEnable, value))
                {
                    OnUiStateChanged(value);
                }
            }
        }

        /*

        public NeedleCameraPrintViewModel(IParameterManager parameterManager, GlobalParam globalParam, HardwareManager hardwareManager, SafeAxisMotion safeAxisMotion)
        {
            _currentNeedleOffsetPoint = new MPoint();
            CurrentNeedlePoint = new MPoint();
            _cameraPoint = new MPoint();
            _workPos = new List<Point>();
            _device = hardwareManager;
            _safeMotion = safeAxisMotion;
            _globalParam = globalParam;
            _paramList = parameterManager as IParamList;
            _needlePrintCalibrateSetting = _globalParam.NeedlePrintCalibrateSetting;
            _needlePrintCalibrateParameter = _needlePrintCalibrateSetting.NeedlePrintCalibrateParameter;
            SetSpeed(50);
            CalculteWorkPos();
            maintanceRecord = new MaintanceRecord()
            {
                DeviceId = LogManager.MachineID,
                MaintanceType = MaintanceType.针印验证,
            };
        }
        protected override void OnViewLoaded()
        {
            base.OnViewLoaded();
            NeedlePrintCalibrateParameter = _needlePrintCalibrateSetting.NeedlePrintCalibrateParameter;
            var needleCalibrationSetting = _globalParam.NeedleCalibrationSetting;
            CurrentNeedleOffsetPoint.X = needleCalibrationSetting.NeedleXYCalibrationItem.OffsetX;
            CurrentNeedleOffsetPoint.Y = needleCalibrationSetting.NeedleXYCalibrationItem.OffsetY;
        }
        public void SpeedChanged(object sender, EventArgs eventArgs)
        {
            if (sender is RadioButton radioButton)
            {
                if (radioButton.Tag != null)
                {
                    var speed = Convert.ToInt32(radioButton.Tag);
                    SetSpeed(speed);
                }

            }
        }
        private void SetSpeed(double speed)
        {
            _safeMotion.SetAxisSpeed(_device.Axis_X1, speed);
            _safeMotion.SetAxisSpeed(_device.Axis_Y1, speed);
            _safeMotion.SetAxisSpeed(_device.Axis_X2, speed);
            _safeMotion.SetAxisSpeed(_device.Axis_Y2, speed);
            _safeMotion.SetAxisSpeed(_device.Axis_Z1, _z1Speed);
        }
        public void MoveToOrginPos()
        {
            CommonUti.RunOnUi(() =>
            {
                MoveOrgin();
            });
        }
        public void TeachWSPos()
        {
            CommonUti.RunOnUi(() =>
            {
                NeedlePrintCalibrateParameter.AvoidancePoint.X = _device.Axis_X2.GetPositionImmediate();
                NeedlePrintCalibrateParameter.AvoidancePoint.Y = _device.Axis_Y2.GetPositionImmediate();
            });
        }
        public void MoveToWsPos()
        {
            CommonUti.RunOnUi(() =>
            {
                MoveAvoidancePos();
            });
        }
        public void TeachZ1Pos()
        {
            CommonUti.RunOnUi(() =>
            {
                NeedlePrintCalibrateParameter.Z1WorkHeight = _device.Axis_Z1.GetPositionImmediate();
            });
        }
        public void MoveToZ1Pos()
        {
            CommonUti.RunOnUi(() =>
            {
                MoveZ1Pos();
            });
        }
        public void TeachZ2Pos()
        {
            CommonUti.RunOnUi(() =>
            {
                NeedlePrintCalibrateParameter.Z2WorkHeight = _device.Axis_Z2.GetPositionImmediate();
            });
        }
        public void MoveToZ2Pos()
        {
            CommonUti.RunOnUi(() =>
            {
                MoveZ2Pos();
            });
        }
        public void TeachStartPos()
        {
            CommonUti.RunOnUi(() =>
            {
                NeedlePrintCalibrateParameter.StartPoint.X = _device.Axis_X1.GetPositionImmediate();
                NeedlePrintCalibrateParameter.StartPoint.Y = _device.Axis_Y1.GetPositionImmediate();
            });
        }

        public void MoveToStartPos()
        {
            CommonUti.RunOnUi(() =>
            {
                _safeMotion.MoveAxis(new AxisPos
                {
                    Axis = _device.Axis_X11,
                    Pos = NeedlePrintCalibrateParameter.StartPoint.PointX
                }, new AxisPos
                {
                    Axis = _device.Axis_Y11,
                    Pos = NeedlePrintCalibrateParameter.StartPoint.PointY
                });
            });
        }
        public void TeachEndPos()
        {
            CommonUti.RunOnUi(() =>
            {
                NeedlePrintCalibrateParameter.EndPoint.X = _device.Axis_X1.GetPositionImmediate();
                NeedlePrintCalibrateParameter.EndPoint.Y = _device.Axis_Y1.GetPositionImmediate();
            });
        }
        public void MoveToEndPos()
        {
            CommonUti.RunOnUi(() =>
            {
                _safeMotion.SafeMove(new MotionData
                {
                    Name = "X1",
                    TargetPosition = NeedlePrintCalibrateParameter.EndPoint.X
                }, new MotionData
                {
                    Name = "y1",
                    TargetPosition = NeedlePrintCalibrateParameter.EndPoint.Y
                });
            });
        }
        private void MoveOrgin()
        {
            _safeMotion.SafeMoveAxis(new AxisPos
            {
                Axis = _device.Axis_CY,
                Pos = 0
            }, new AxisPos
            {
                Axis = _device.Axis_CZ,
                Pos = 0
            });
        }
        private void MoveAvoidancePos()
        {
            _safeMotion.MoveAxis(new AxisPos
            {
                Axis = _device.Axis_X21,
                Pos = NeedlePrintCalibrateParameter.AvoidancePoint.PointX
            }, new AxisPos
            {
                Axis = _device.Axis_Y21,
                Pos = NeedlePrintCalibrateParameter.AvoidancePoint.PointY
            });
        }
        private void MoveZ1Pos()
        {
            _safeMotion.MoveAxis(new AxisPos
            {
                Axis = _device.Axis_Z1,
                Pos = NeedlePrintCalibrateParameter.Z1WorkHeight
            });
        }
        private void MoveZ2Pos()
        {
            _safeMotion.MoveAxis(new AxisPos
            {
                Axis = _device.Axis_Z2,
                Pos = NeedlePrintCalibrateParameter.Z2WorkHeight
            });
        }
        private void MoveAvoidanceAndWorkPos(Point workP)
        {
            _safeMotion.MoveAxis(new AxisPos
            {
                Axis = _device.Axis_X21,
                Pos = NeedlePrintCalibrateParameter.AvoidancePoint.PointX
            }, new AxisPos
            {
                Axis = _device.Axis_Y21,
                Pos = NeedlePrintCalibrateParameter.AvoidancePoint.PointY
            }, new AxisPos
            {
                Axis = _device.Axis_X11,
                Pos = workP.X
            }, new AxisPos
            {
                Axis = _device.Axis_Y11,
                Pos = workP.Y
            });
        }
        public void StartVerify()
        {
            CommonUti.RunOnUi(() =>
            {
                InitCancelToken();
                if (_workPos.Count == 0)
                {
                    MaxwellControl.Controls.MessageBox.Show("无法计算有效的下扎点，请检查铜箔示教的起始点坐标");
                    return;
                }
                if (_workPos.Count <= NeedlePrintCalibrateParameter.UsedNum)
                {
                    MaxwellControl.Controls.MessageBox.Show("当前铜箔已用完，请确认是否需要更换");
                }
                IoC.Get<IProjectManager>().EnablePageAndDisableOther("刺晶头校正");
                VisionParData visionParData = new VisionParData
                {
                    LightSourceBack = 0,
                    LightSourceRingBlue = 255,
                    LightSourcePointBlue = 255,
                    LightSourcePointRed = 255,
                    LightSourceRingRed = 255,
                };
                _safeMotion.MoveZToEscape();
                visionParData.SetLightData();
                CheckCancel();
                var workPoint = _workPos[NeedlePrintCalibrateParameter.UsedNum];
                CurrentNeedlePoint.PointX = workPoint.X;
                CurrentNeedlePoint.PointY = workPoint.Y;
                MoveOrgin();
                MoveAvoidanceAndWorkPos(workPoint);
                MoveZ1Pos();
                CheckCancel();
                Thread.Sleep(NeedlePrintCalibrateParameter.SleepTime);
                _safeMotion.Z1MoveToEscape();
                CheckCancel();
                var cameraPoint = IoC.Get<VisionOperation>().GetCameraRulerPointByRulerNeedle(new Point(_device.Axis_X11.GetPositionImmediate(), _device.Axis_Y11.GetPositionImmediate()));
                _safeMotion.SafeMoveAxis(new AxisPos
                {
                    Axis = _device.Axis_X11,
                    Pos = cameraPoint.X
                }, new AxisPos
                {
                    Axis = _device.Axis_Y11,
                    Pos = cameraPoint.Y
                });
                MoveZ2Pos();
                NeedlePrintCalibrateParameter.UsedNum++;
                _needlePrintCalibrateSetting.Write();
            }, exceptionHandler: ex =>
            {
                _safeMotion.MoveZToEscape();
                CommonUti.ShowMessageBox(ex);
            }, begainAction: () =>
            {
                UiEnable = false;
            }, afterAction: () =>
            {
                UiEnable = true;
                IoC.Get<IProjectManager>().SwitchState();
            });
        }

        private void InitCancelToken()
        {
            if (_cancellationTokenSource != null)
            {
                _cancellationTokenSource.Cancel();
                _cancellationTokenSource.Dispose();
            }
            _cancellationTokenSource = new CancellationTokenSource();
        }

        private void CheckCancel()
        {
            _cancellationTokenSource.Token.ThrowIfCancellationRequested();
        }
        public void StopVerify()
        {
            _cancellationTokenSource?.Cancel();
            IoC.Get<CancelSourceManager>().CancelMotionAndCheck();
            IoC.Get<GlobalDeviceService>().StopMainAxis();
        }

        public void void NeedleAlignment()
        {
            CommonUti.RunOnUi(() =>
            {
                var needlePoint = IoC.Get<VisionOperation>().GetNeedleRulerPointByRulerCamera(new Point(_device.Axis_X11.GetPositionImmediate(), _device.Axis_Y11.GetPositionImmediate()));
                _safeMotion.SafeMoveAxis(new AxisPos
                {
                    Axis = _device.Axis_X11,
                    Pos = needlePoint.X
                }, new AxisPos
                {
                    Axis = _device.Axis_Y11,
                    Pos = needlePoint.Y
                });
            });
        }
        public void void CameraAlignment()
        {
            CommonUti.RunOnUi(() =>
            {
                var cameraPoint = IoC.Get<VisionOperation>().GetCameraRulerPointByRulerNeedle(new Point(_device.Axis_X11.GetPositionImmediate(), _device.Axis_Y11.GetPositionImmediate()));
                _safeMotion.SafeMoveAxis(new AxisPos
                {
                    Axis = _device.Axis_X11,
                    Pos = cameraPoint.X
                }, new AxisPos
                {
                    Axis = _device.Axis_Y11,
                    Pos = cameraPoint.Y
                });
            });
        }
        public void SaveParam()
        {
            CommonUti.RunOnUi(() =>
            {
                CalculteWorkPos();
                if (_workPos.Count == 0)
                {
                    MaxwellControl.Controls.MessageBox.Show("无法计算有效的下扎点，请检查铜箔示教的起始点坐标");
                    return;
                }
                _needlePrintCalibrateSetting.Write();
                Application.Current.Dispatcher.Invoke(() =>
                {
                    ParameterHelper.RaiseValueAccept();
                });
                MaxwellControl.Controls.MessageBox.Show("操作成功");
            });

        }

        public void ResetRecord()
        {
            NeedlePrintCalibrateParameter.UsedNum = 0;
            SaveParam();
        }

        public void TeachCameraPos()
        {
            CameraPoint.PointX = _device.Axis_X11.GetPositionImmediate();
            CameraPoint.PointY = _device.Axis_Y11.GetPositionImmediate();
        }
        public void CalculateOffset()
        {
            CommonUti.RunOnUi(() =>
            {
                if (CameraPoint.PointX == 0 || CameraPoint.PointY == 0 || CurrentNeedlePoint.PointX == 0 || CurrentNeedlePoint.PointY == 0)
                {
                    MaxwellControl.Controls.MessageBox.Show("请先示教相机位置和针尖位置");
                    return;
                }
                List<Point> cameraRealPointList = new List<Point>();
                List<Point> needleRealPointList = new List<Point>();
                VisionOperation visionOperation = IoC.Get<VisionOperation>();

                Point cameraPointReal = visionOperation.GetRealByRuler(_device.Camera_Extend.Id, new Point(CameraPoint.PointX, CameraPoint.PointY));
                Point needlePointReal = visionOperation.GetRealByRuler(_device.Camera_Extend.Id, new Point(CurrentNeedlePoint.PointX, CurrentNeedlePoint.PointY));
                var needleCalibrationSetting = _paramList.GetParameter<NeedleCalibrationSetting>();
                needleCalibrationSetting.NeedleXYCalibrationItem.InitialOffsetX = needlePointReal.X - cameraPointReal.X;
                needleCalibrationSetting.NeedleXYCalibrationItem.InitialOffsetY = needlePointReal.Y - cameraPointReal.Y;
                var offsetX = needleCalibrationSetting.NeedleXYCalibrationItem.OffsetX - needleCalibrationSetting.NeedleXYCalibrationItem.InitialOffsetX;
                var offsetY = needleCalibrationSetting.NeedleXYCalibrationItem.OffsetY - needleCalibrationSetting.NeedleXYCalibrationItem.InitialOffsetY;
                if (Math.Abs(offsetY) >= 2 || Math.Abs(offsetX) > 2.5)
                {
                    MaxwellControl.Controls.MessageBox.Show("当前相机与针尖偏差过大，请重新校准！");
                    return;
                }
                needleCalibrationSetting.NeedleXYCalibrationItem.OffsetX = needleCalibrationSetting.NeedleXYCalibrationItem.CompensateX + needleCalibrationSetting.NeedleXYCalibrationItem.InitialOffsetX;
                needleCalibrationSetting.NeedleXYCalibrationItem.OffsetY = needleCalibrationSetting.NeedleXYCalibrationItem.CompensateY + needleCalibrationSetting.NeedleXYCalibrationItem.InitialOffsetY;

                CurrentNeedleOffsetPoint.PointX = needleCalibrationSetting.NeedleXYCalibrationItem.OffsetX;
                CurrentNeedleOffsetPoint.PointY = needleCalibrationSetting.NeedleXYCalibrationItem.OffsetY;

                EquipmentParaSysSetting equipmentParaSysSetting = _paramList.GetParameter<EquipmentParaSysSetting>();
                equipmentParaSysSetting.SafeParaSysItem.NeedleCameraOffsetX = needleCalibrationSetting.NeedleXYCalibrationItem.OffsetX;
                equipmentParaSysSetting.SafeParaSysItem.NeedleCameraOffsetY = needleCalibrationSetting.NeedleXYCalibrationItem.OffsetY;
                equipmentParaSysSetting.Write();
                needleCalibrationSetting.Write();
                maintanceRecord.WriteToFile($"当前相机与针尖与上次偏差 X：{offsetX} Y:{offsetY}");
                MaxwellControl.Controls.MessageBox.Show("操作成功");

            });
        }
        private void CalculteWorkPos()
        {
            _workPos.Clear();
            var startPoint = new Point(NeedlePrintCalibrateParameter.StartPoint.X, NeedlePrintCalibrateParameter.StartPoint.PointY);
            var width = NeedlePrintCalibrateParameter.EndPoint.X - NeedlePrintCalibrateParameter.StartPoint.X;
            var height = NeedlePrintCalibrateParameter.EndPoint.Y - NeedlePrintCalibrateParameter.StartPoint.Y;
            var xscale = width > 0 ? 1 : -1;
            var yscale = height > 0 ? 1 : -1;
            var xcount = Math.Floor(Math.Abs(width) / NeedlePrintCalibrateParameter.Xpitch);
            var ycount = Math.Floor(Math.Abs(height) / NeedlePrintCalibrateParameter.Ypitch);
            for (int i = 0; i < ycount; i++)
            {
                for (int j = 0; j < xcount; j++)
                {
                    var cameraPoint = new Point
                    {
                        X = startPoint.X + xscale * i * NeedlePrintCalibrateParameter.Xpitch,
                        Y = startPoint.Y + yscale * j * NeedlePrintCalibrateParameter.Ypitch,
                    };

                    var needlePoint = IoC.Get<VisionOperation>().GetNeedleRulerPointByRulerCamera(cameraPoint);
                    _workPos.Add(needlePoint);
                }
            }
        }

        */

        private bool CheckPointInRange(Point point)
        {
            return IsPointInRange(NeedlePrintCalibrateParameter.StartPoint, NeedlePrintCalibrateParameter.EndPoint, point);
        }

        bool IsPointInRange(MPoint p1, MPoint p2, Point current)
        {
            // 计算最小和最大 X 和 Y 值
            double minX = Math.Min(p1.X, p2.X);
            double maxX = Math.Max(p1.X, p2.X);
            double minY = Math.Min(p1.Y, p2.Y);
            double maxY = Math.Max(p1.Y, p2.Y);

            // 检查待判断的点是否在范围内
            return (current.X >= minX && current.X <= maxX) && (current.Y >= minY && current.Y <= maxY);
        }
    }
}
