using MainShell.AlgorithmCalib.Common;
using MainShell.AlgorithmCalib.Model;
using MainShell.Hardware;
using MainShell.Log;
using SemiconductorVisionAlgorithm.SemiParams;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MainShell.AlgorithmCalib.Service
{
    /// <summary>
    /// 融合标定后处理器（Die/Pad共用）
    /// 通过 IsWaferCalib 内部区分行为
    /// </summary>
    public class FusionCalibPostProcessor : IAlgorithmCalibrationPostProcessor
    {
        private readonly FusionCalibMotionService _motionService;
        private readonly HardwareManager _hardware;
        private readonly FusionCalibModuleItem _moduleItem;
        private readonly Func<Rectangle1> _roiRectProvider;

        public event EventHandler<CalibrationProgressEventArgs> ProgressChanged;

        private Point[,] _initialwsPos;
        private Dictionary<int, Point[,]> _calibResultPointData = new Dictionary<int, Point[,]>();
        private List<double> _calibPosList = new List<double>();

        public string Name => "FusionCalib";

        public FusionCalibPostProcessor(
            FusionCalibMotionService motionService,
            HardwareManager hardware,
            FusionCalibModuleItem moduleItem,
            Func<Rectangle1> roiRectProvider)
        {
            _motionService = motionService ?? throw new ArgumentNullException(nameof(motionService));
            _hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
            _moduleItem = moduleItem ?? throw new ArgumentNullException(nameof(moduleItem));
            _roiRectProvider = roiRectProvider;
        }

        public async Task ExecuteAsync(AlgorithmCalibExecutionResult calibrationResult, CancellationToken cancellationToken)
        {
            $"{(_moduleItem.IsWaferCalib ? "Die" : "Pad")}融合标定开始。".LogInfo();

            try
            {
                _calibResultPointData.Clear();
                _calibPosList.Clear();

                double waferStep = _moduleItem.CalibStep;
                string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _moduleItem.ModelPath);

                int totalSteps = _moduleItem.Count + 1;
                ReportProgress("采集初始网格点...", 0, totalSteps);

                // 1. 初始网格
                _initialwsPos = await Task.Run(() =>
                    ApprochTable(waferStep,
                        _moduleItem.MoveAxisPos,
                        GetCurrentY1(),
                        _moduleItem.ApproachXPos,
                        _moduleItem.ApproachYPos,
                        0, path, cancellationToken),
                    cancellationToken);

                // 2. 循环采集
                for (int i = 0; i < _moduleItem.Count; i++)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    ReportProgress($"采集第 {i + 1}/{_moduleItem.Count} 组...", i + 1, totalSteps);

                    double x1, y1, x2, y2;
                    CalculatePositions(i, out x1, out y1, out x2, out y2);

                    Point[,] points = await Task.Run(() =>
                        ApprochTable(waferStep, x1, y1, x2, y2, i + 1, path, cancellationToken),
                        cancellationToken);

                    _calibResultPointData[i] = points;
                    _calibPosList.Add(GetCurrentMoveAxisPos());
                }

                // 3. 调用平台算法
                ReportProgress("计算融合矩阵...", totalSteps, totalSteps);
                await Task.Run(() =>
                {
                    string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CalibData");

                    if (_moduleItem.IsWaferCalib)
                    {
                        SemiJM1Vision.SemiJM1Manager.Instance.cal_wafer_fusion_die(
                            _calibResultPointData, _calibPosList, _initialwsPos,
                            _moduleItem.CalibStep, waferStep, _moduleItem.CalibCount);
                    }
                    else
                    {
                        SemiJM1Vision.SemiJM1Manager.Instance.cal_wafer_fusion_pad(
                            _moduleItem.Index, _calibResultPointData, _calibPosList, _initialwsPos,
                            _moduleItem.CalibStep, waferStep, _moduleItem.CalibCount);
                        SemiJM1Vision.SemiJM1Manager.Instance.set_center(new Point(0, 0));
                    }

                    SemiJM1Vision.SemiJM1Manager.Instance.Save(filePath);
                }, cancellationToken);

                $"{(_moduleItem.IsWaferCalib ? "Die" : "Pad")}融合标定完成。".LogInfo();
            }
            catch (OperationCanceledException)
            {
                "融合标定已取消。".LogInfo();
                throw;
            }
            catch (Exception ex)
            {
                $"融合标定失败：{ex.Message}".LogSysError();
                throw;
            }
        }

        public async Task VerifyAsync(CancellationToken cancellationToken)
        {
            // TODO: 验证流程
            await Task.CompletedTask;
        }

        #region 位置计算（Die/Pad分支）

        private void CalculatePositions(int stepIndex, out double x1, out double y1, out double x2, out double y2)
        {
            if (_moduleItem.IsWaferCalib)
            {
                // Die: 移动X1，逼近X2+Y1
                x1 = _moduleItem.CameraAxisPos + _moduleItem.Step * stepIndex;
                y1 = _moduleItem.StartY;
                x2 = _moduleItem.StartX + _moduleItem.Step * stepIndex;
                y2 = _hardware.Axis_Y2.State.ActualPos;
            }
            else
            {
                // Pad: 移动Y1，逼近X1+Y2
                x1 = _moduleItem.StartX;
                y1 = _moduleItem.CameraAxisPos + _moduleItem.Step * stepIndex;
                x2 = _hardware.Axis_X2.State.ActualPos;
                y2 = _moduleItem.StartY + _moduleItem.Step * stepIndex;
            }
        }

        private double GetCurrentY1()
        {
            return _hardware.Axis_Y1.State.ActualPos;
        }

        private double GetCurrentMoveAxisPos()
        {
            return _moduleItem.IsWaferCalib
                ? _hardware.Axis_X1.State.ActualPos
                : _hardware.Axis_Y1.State.ActualPos;
        }

        #endregion

        #region 网格采集

        private Point[,] ApprochTable(double calibStep, double x1, double y1, double x2, double y2,
            int count, string path, CancellationToken ct)
        {
            int calibCount = _moduleItem.CalibCount;
            Point[,] pointArray = new Point[calibCount, calibCount];

            // 先移到起始位置
            if (_moduleItem.IsWaferCalib)
                _motionService.MoveWsAvoidance(x2, y1);
            else
                _motionService.MovePhsAvoidance(x1, y2);

            for (int y = 0; y < calibCount; y++)
            {
                double Y1 = y * calibStep + y1;
                double Y2 = y * calibStep + y2;

                for (int x = 0; x < calibCount; x++)
                {
                    ct.ThrowIfCancellationRequested();

                    int index = y % 2 == 0 ? x : calibCount - 1 - x;
                    double X2 = index * calibStep + x2;
                    double X1 = index * calibStep + x1;

                    if (_moduleItem.IsWaferCalib)
                    {
                        _motionService.MoveWsAvoidance(X2, Y1);
                        // TODO: 调用逼近识别
                        pointArray[index, y] = new Point(
                            _hardware.Axis_X2.State.ActualPos,
                            _hardware.Axis_Y1.State.ActualPos);
                    }
                    else
                    {
                        _motionService.MovePhsAvoidance(X1, Y2);
                        // TODO: 调用逼近识别
                        pointArray[index, y] = new Point(
                            _hardware.Axis_X1.State.ActualPos,
                            _hardware.Axis_Y2.State.ActualPos);
                    }
                }
            }

            return pointArray;
        }

        #endregion

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