using MainShell.AlgorithmCalib.Common;
using MainShell.AlgorithmCalib.Model;
using MainShell.Common;
using MainShell.Hardware;
using MainShell.Log;
using MainShell.Motion;
using SemiconductorVisionAlgorithm.SemiParams;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using SemiPoint = SemiconductorVisionAlgorithm.SemiParams.Point;

namespace MainShell.AlgorithmCalib.Service
{
    /// <summary>
    /// 融合对位处理器
    /// 3步对位流程：
    ///   1. 抓Pad点（框选ROI识别Pad坐标）
    ///   2. Die网格飞拍（首点+参数 → 蛇形扫描获取x*y个Die点）
    ///   3. 对位验证（选择一个Die点 → 与Pad点对位 → 输出结果）
    /// </summary>
    public class FusionAlignProcessor
    {
        private readonly FusionCalibMotionService _motionService;
        private readonly HardwareManager _hardware;
        private readonly FusionCalibModuleItem _moduleItem;
        private readonly ApproachAlignmentService _approachAlignmentService;

        // 飞拍参数
        private double _flyScanStartX;
        private double _flyScanStartY;
        private int _flyScanXCount;
        private int _flyScanYCount;
        private double _flyScanStep;

        public event EventHandler<CalibrationProgressEventArgs> ProgressChanged;
        private readonly Func<Rectangle1> _roiRectProvider;  // ROI 提供者委托


        public FusionAlignProcessor(
            FusionCalibMotionService motionService,
            HardwareManager hardware,
            FusionCalibModuleItem moduleItem,
            Func<Rectangle1> roiRectProvider)
        {
            _motionService = motionService;
            _hardware = hardware;
            _moduleItem = moduleItem;
            _approachAlignmentService = IoC.Get<ApproachAlignmentService>();
            _roiRectProvider = roiRectProvider;
        }

        /// <summary>
        /// 设置飞拍参数
        /// </summary>
        public void SetFlyScanParams(double startX, double startY, int xCount, int yCount, double step)
        {
            _flyScanStartX = startX;
            _flyScanStartY = startY;
            _flyScanXCount = xCount;
            _flyScanYCount = yCount;
            _flyScanStep = step;
        }

        /// <summary>
        /// 步骤1：抓Pad点
        /// 框选ROI区域，识别Pad目标点坐标（pad运动系：X1,Y2）
        /// </summary>
        public async Task CapturePadPointAsync(CancellationToken cancellationToken)
        {
            await Task.Run(async () =>
            {
                ReportProgress("抓Pad点...", 1, 3);

                bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
                if (!success)
                {
                    throw new InvalidOperationException($"逼近对齐失败");
                }

                _moduleItem.PadRealX = _hardware.Axis_X1.State.ActualPos;
                _moduleItem.PadRealY = _hardware.Axis_Y2.State.ActualPos;

                "抓Pad点完成".LogInfo();
            }, cancellationToken);
        }

        /// <summary>
        /// 步骤2a：抓Die首点
        /// 框选ROI区域，识别Die首点坐标（die运动系：X2,Y1）
        /// </summary>
        public async Task CaptureDieFirstPointAsync(CancellationToken cancellationToken)
        {
            await Task.Run(async() =>
            {
                ReportProgress("抓Die首点...", 1, 3);

                bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
                if (!success)
                {
                    throw new InvalidOperationException($"逼近对齐失败");
                }

                _moduleItem.DieRealX = _hardware.Axis_X2.State.ActualPos;
                _moduleItem.DieRealY = _hardware.Axis_Y1.State.ActualPos;

                "抓Die首点完成".LogInfo();
            }, cancellationToken);
        }

        /// <summary>
        /// 步骤2b：Die网格飞拍
        /// 以首点为起点，按step和count执行蛇形网格飞拍，获取x*y个Die点
        /// </summary>
        public async Task ExecuteDieGridFlyScanAsync(CancellationToken cancellationToken)
        {
            await Task.Run(async() =>
            {
                var sw = Stopwatch.StartNew();
                int totalPoints = _flyScanXCount * _flyScanYCount;
                int captured = 0;

                ReportProgress($"开始飞拍，网格{_flyScanXCount}×{_flyScanYCount}，共{totalPoints}点...", 0, totalPoints);

                // 清空之前的数据
                _moduleItem.DieGridPoints = new List<Tuple<int, int, SemiPoint>>();

                for (int row = 0; row < _flyScanYCount; row++)
                {
                    // 蛇形扫描：偶数行从左到右，奇数行从右到左
                    for (int col = 0; col < _flyScanXCount; col++)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        int actualCol = row % 2 == 0 ? col : (_flyScanXCount - 1 - col);

                        // 计算目标位置
                        double targetX2 = _flyScanStartX + actualCol * _flyScanStep;
                        double targetY1 = _flyScanStartY + row * _flyScanStep;

                        // 移动轴到目标位置
                        _motionService.MoveWsAvoidance(targetX2, targetY1);

                        // 等待运动完成
                        Thread.Sleep(200);

                        bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
                        if (!success)
                        {
                            throw new InvalidOperationException($"逼近对齐失败");
                        }

                        // 读取当前位置
                        double currentX2 = _hardware.Axis_X2.State.ActualPos;
                        double currentY1 = _hardware.Axis_Y1.State.ActualPos;


                        SemiPoint point = new SemiPoint(currentX2, currentY1);
                        _moduleItem.DieGridPoints.Add(Tuple.Create(row, actualCol, point));

                        captured++;
                        ReportProgress($"飞拍中... ({captured}/{totalPoints})", captured, totalPoints);
                    }
                }

                sw.Stop();
                $"Die网格飞拍完成，共{captured}点，耗时{sw.ElapsedMilliseconds}ms".LogInfo();
            }, cancellationToken);
        }

        /// <summary>
        /// 步骤3：执行对位
        /// 用户选择网格中的一个Die点（row, col），与Pad点执行对位
        /// 对位流程：Die X对齐Pad → Pad Y对齐Die → X2补偿
        /// </summary>
        public async Task ExecuteAlignAsync(CancellationToken ct, int selectedRow, int selectedCol)
        {
            await Task.Run(() =>
            {
                ReportProgress("执行对位...", 1, 6);

                // 从网格中找到选中的Die点
                SemiPoint selectedDie = null;
                foreach (var pt in _moduleItem.DieGridPoints)
                {
                    if (pt.Item1 == selectedRow && pt.Item2 == selectedCol)
                    {
                        selectedDie = pt.Item3;
                        break;
                    }
                }

                if (selectedDie == null)
                {
                    throw new Exception($"未找到Die点[{selectedRow},{selectedCol}]");
                }

                // 使用选中的Die点作为对位基准
                _moduleItem.DieRealX = selectedDie.X;
                _moduleItem.DieRealY = selectedDie.Y;
                _moduleItem.PadRealX = _moduleItem.PadRulerX;
                _moduleItem.PadRealY = _moduleItem.PadRulerY;

                ReportProgress("Die X方向对齐Pad...", 2, 6);

                // === 步骤3a：Die X方向对齐Pad ===
                // 查die融合表，将Die的X方向对齐到Pad的X方向
                // 移动X2,Y1 → Y1会产生少许偏移
                //
                // TODO: 接入JM1融合表查询
                // SemiPoint dieReal = new SemiPoint(_moduleItem.DieRealX, _moduleItem.DieRealY);
                // SemiPoint padReal = new SemiPoint(_moduleItem.PadRealX, _moduleItem.PadRealY);
                // SemiJM1Manager.Instance.get_ws_pos_die(dieReal, padReal, out SemiPoint wsTarget);
                //
                // 暂时模拟：使用Die坐标作为目标
                double wsTargetX = _moduleItem.DieRealX;
                double wsTargetY = _moduleItem.DieRealY;

                _motionService.MoveWsAvoidance(wsTargetX, wsTargetY);

                // 读取此时Y1位置（已产生偏移）
                double currentY1 = _hardware.Axis_Y1.State.ActualPos;

                ReportProgress("Pad Y方向对齐Die...", 3, 6);

                // === 步骤3b：Pad Y方向对齐Die ===
                // 根据当前Y1值，查pad融合表，计算X1,Y2目标位置
                // 移动X1,Y2 → X1会产生少许偏移
                //
                // TODO: 接入pad融合表查询
                // SemiPoint padTarget = FusionTableLookupPad(padReal, currentY1);
                //
                // 暂时模拟
                double padTargetX = _moduleItem.PadRealX;
                double padTargetY = _moduleItem.PadRealY;

                _motionService.MovePhsAvoidance(padTargetX, padTargetY);

                // 读取此时X1位置（已产生偏移）
                double currentX1 = _hardware.Axis_X1.State.ActualPos;

                ReportProgress("X2补偿...", 4, 6);

                // === 步骤3c：X2补偿 ===
                // X2跟上X1的移动量
                double x1Delta = currentX1 - _moduleItem.PadRulerX;
                double x2Target = wsTargetX + x1Delta;

                _motionService.SafeMove(_hardware.Axis_X2, x2Target);

                // 记录结果
                _moduleItem.AlignResultX = currentX1;
                _moduleItem.AlignResultY = currentY1;
                _moduleItem.AlignResultX2 = x2Target;

                ReportProgress("对位完成", 5, 6);
                $"对位完成: Die[{selectedRow},{selectedCol}] → Pad, X1={currentX1:F4}, Y1={currentY1:F4},  X2 ={ x2Target: F4}".LogInfo();
              }, ct);
        }

        private void ReportProgress(string message, int current, int total)
        {
            ProgressChanged?.Invoke(this, new CalibrationProgressEventArgs
            {
                Message = message,
                Current = current,
                Total = total
            });
        }

        /// <summary>
        /// 逼近对齐
        /// </summary>
        private async Task<bool> ApproachAtPointAsync(CancellationToken cancellationToken)
        {
            Rectangle1 roiRect = _roiRectProvider?.Invoke();
            var request = new ApproachAlignmentRequest(
                axes: new[]
                {
                      new ApproachAlignmentAxis(_hardware.Axis_X2.Name,  0.005),
                      new ApproachAlignmentAxis(_hardware.Axis_Y1.Name,  0.005)
                },
                camera: CameraType.TopPositionCamera)
            {
                MaxIterations = 3,
                RecognitionTimeoutMilliseconds = 5000,
                RecognitionParameters = new CenterRecognitionParameters()
                {
                    Type = CenterRecognitionType.EdgeCircle,
                    rectangle = roiRect
                }
            };

            var result = await _approachAlignmentService.ApproachAlignmentAsync(request, cancellationToken).ConfigureAwait(false);
            return result.Succeeded;
        }
    }
}