using JM1.VisionModule;
using MainShell.AlgorithmCalib.Model;
using MainShell.AlgorithmCalib.Service;
using MainShell.AlgorithmCalib.View;
using MainShell.Common;
using MainShell.Common.Display.ViewModel;
using MainShell.Filewritable;
using MainShell.Hardware;
using MainShell.Recipe.Models;
using MainShell.Recipe.ViewModel;
using Maxwell.SemiFramework.WaferCalibration.ViewModel;
using MaxwellFramework.Core.Interfaces;
using MwFramework.Controls.SystemCalib;
using MwFramework.Controls.UIControl;
using MwFramework.ManagerService;
using SemiconductorVisionAlgorithm.SemiParams;
using Stylet;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
using CameraAxisViewModel = MainShell.Common.Display.ViewModel.CameraAxisViewModel;
using Point = SemiconductorVisionAlgorithm.SemiParams.Point;

namespace MainShell.AlgorithmCalib.ViewModel
{
    public class MotionMultipleCalibViewModel:Screen,IPage
    {
        #region 常量

        private const int CalibAreaCount = 5;
        private const string PointsFileExt = ".csv";
        private const string AreaFilePrefix = "Camera_Area";

        #endregion

        #region 字段

        private readonly HashSet<string> _forceCloseIds = new HashSet<string>();
        private readonly Dictionary<string, Window> _calibWindows = new Dictionary<string, Window>();
        private readonly MotionFusion _motionFusion = new MotionFusion();
        private List<Point> _calibResultRealPoint = new List<Point>();
        private List<Point> _calibResultAxisPoint = new List<Point>();
        private bool _isDataLoaded = false;

        #endregion

        #region 属性

        public string Name { get; set; } = "MotionMenuCalib";
        public string CalibName { get; set; }
        public string FileSaveDir { get; set; }

        private CameraAxisViewModel _cameraAxisViewModelService;
        public CameraAxisViewModel CameraAxisViewModelService
        {
            get => _cameraAxisViewModelService;
            set => SetAndNotify(ref _cameraAxisViewModelService, value);
        }

        private DelegateBase _motion = new DelegateBase();
        public DelegateBase Motion
        {
            get => _motion;
            set => SetAndNotify(ref _motion, value);
        }

        private ObservableCollection<MotionSysDataItem> _motionCalibParItem = new ObservableCollection<MotionSysDataItem>();
        public ObservableCollection<MotionSysDataItem> MotionCalibParItem
        {
            get => _motionCalibParItem;
            set => SetAndNotify(ref _motionCalibParItem, value);
        }

        private MotionSysDataItem _selectedCalibPar;
        public MotionSysDataItem SelectedCalibPar
        {
            get => _selectedCalibPar;
            set => SetAndNotify(ref _selectedCalibPar, value);
        }

        private List<HardwareDevice> _hardware;
        public List<HardwareDevice> Hardware
        {
            get => _hardware;
            set
            {
                SetAndNotify(ref _hardware, value);
                NotifyOfPropertyChange();
            }
        }

        private MotionSysCalibViewModel _service;
        public MotionSysCalibViewModel Service
        {
            get => _service;
            set => SetAndNotify(ref _service, value);
        }

        private bool _isCalibFinished;
        public bool IsCalibFinished
        {
            get => _isCalibFinished;
            set => SetAndNotify(ref _isCalibFinished, value);
        }

        #endregion

        #region 构造 & 工厂

        public MotionMultipleCalibViewModel()
        {
            _cameraAxisViewModelService = IoC.Get<CameraAxisViewModel>();
        }

        public static MotionMultipleCalibViewModel Create(string calibName, string saveFileName, List<HardwareDevice> device)
        {
            var vm = new MotionMultipleCalibViewModel();
            vm.Initialize(calibName, saveFileName, device);
            return vm;
        }

        #endregion

        #region 初始化 & 生命周期

        private void Initialize(string calibName, string saveFileName, List<HardwareDevice> device)
        {
            CalibName = calibName;
            Hardware = device;
            FileSaveDir = Path.Combine(Paths.CalibSettingPath, "motionCalib");

            var paramList = IoC.Get<IParameterManager>() as IParamList;

            Service = new MotionSysCalibViewModel(device, paramList, true)
            {
                IsShowSolidLine = true,
                ShapeThickness = 1,
                DrawInConcurrency = false,
                IsAxisControlLDBVisible = Visibility.Visible
            };
        }

        protected override void OnViewLoaded()
        {
            base.OnViewLoaded();

            if (_hardware != null)
            {
                _cameraAxisViewModelService.CameraAxisDevices.HardwareDeviceList = Hardware;
                NotifyOfPropertyChange(nameof(CameraAxisViewModelService));
            }

            if (!_isDataLoaded)
            {
                ReadCalibData();
                _isDataLoaded = true;
            }
        }




        #endregion

        #region 文件路径辅助

        private string GetXmlPath(int areaIndex) =>
            Path.Combine(FileSaveDir, $"{AreaFilePrefix}{areaIndex}.xml");

        private string GetPointsPath(int areaIndex) =>
            Path.Combine(FileSaveDir, $"{AreaFilePrefix}{areaIndex}{PointsFileExt}");

        #endregion

        #region 打开标定窗口

        public void btnOpenCalibWindow()
        {
            if (SelectedCalibPar == null)
            {
                MwMessageBox.Show("请先选择一组标定数据。", "提示",
                    MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            string calibId = SelectedCalibPar.CalibId;

            // 已有缓存窗口 → 激活显示
            if (_calibWindows.TryGetValue(calibId, out var existingWindow))
            {
                if (existingWindow.WindowState == WindowState.Minimized)
                    existingWindow.WindowState = WindowState.Normal;
                existingWindow.Show();
                existingWindow.Activate();
                return;
            }

            // 首次打开：创建子窗口 VM
            var calibVM = MotionCalibViewModel.Create(
                CalibName, SelectedCalibPar.CameraId, Hardware,
                SelectedCalibPar, SelectedCalibPar.CalibId);
            calibVM.FileSaveDir = FileSaveDir;

            var window = CreateCalibWindow(calibId, calibVM);

            // 写入当前行数据到子窗口
            SyncFields(SelectedCalibPar, calibVM.Service?.SelectedSingleUIData);

            _calibWindows[calibId] = window;
            window.Show();
        }

        private Window CreateCalibWindow(string calibId, MotionCalibViewModel calibVM)
        {
            var calibView = new MotionCalibView { DataContext = calibVM };

            var window = new Window
            {
                Title = $"运动系标定 - {calibId}",
                Width = 1100,
                Height = 750,
                WindowStartupLocation = WindowStartupLocation.CenterOwner,
                Owner = Application.Current.MainWindow,
                ResizeMode = ResizeMode.CanResize,
                Content = calibView
            };

            // 拦截关闭：改为隐藏，保留内存状态
            window.Closing += (s, args) =>
            {
                if (_forceCloseIds.Contains(calibId))
                {
                    _forceCloseIds.Remove(calibId);
                    return; // 允许真正关闭
                }

                args.Cancel = true;
                SyncResultBack(calibVM);
                window.Hide();
            };

            return window;
        }

        #endregion

        #region 数据双向同步

        /// <summary>
        /// 共享的字段映射：将 source 的参数写入 target（单向）
        /// </summary>
        private void SyncFields(MotionSysDataItem source, MotionSysDataItem target)
        {
            if (source == null || target == null) return;

            target.StartAxisX = source.StartAxisX;
            target.StartAxisY = source.StartAxisY;
            target.StartRealX = source.StartRealX;
            target.StartRealY = source.StartRealY;
            target.Rows = source.Rows;
            target.RowStep = source.RowStep;
            target.Columns = source.Columns;
            target.ColumnStep = source.ColumnStep;
            target.XDirSpace = source.XDirSpace;
            target.CameraZPos = source.CameraZPos;
            target.Threshold = source.Threshold;

            // 标定点位用深拷贝，避免子窗口和主页面共享同一引用
            if (source.ResultRealPoints != null && source.ResultRealPoints.Count > 0)
                target.ResultRealPoints = new List<Point>(source.ResultRealPoints);

            if (source.ResultAxisPoints != null && source.ResultAxisPoints.Count > 0)
                target.ResultAxisPoints = new List<Point>(source.ResultAxisPoints);
        }

        /// <summary>
        /// 子窗口关闭时：子窗口 → 主页面对应行
        /// </summary>
        private void SyncResultBack(MotionCalibViewModel calibVM)
        {
            var innerData = calibVM.Service?.SelectedSingleUIData;
            if (innerData == null) return;

            var target = MotionCalibParItem.FirstOrDefault(p => p.CalibId == calibVM.CalibId);
            if (target == null) return;

            SyncFields(innerData, target);
            OnPropertyChanged(nameof(MotionCalibParItem));
        }

        #endregion

        #region 保存数据

        public void btnSaveCalibData()
        {
            var result = MwMessageBox.Show("确认保存当前全部标定数据？", "确认保存",
                MessageBoxButton.YesNo, MessageBoxImage.Warning);

            if (result == MessageBoxResult.Yes)
            {
                if (SaveCalibData())
                {
                    MwMessageBox.Show("保存标定数据成功！", "提示",
                        MessageBoxButton.OK, MessageBoxImage.Information);
                }
                else
                {
                    MwMessageBox.Show("保存标定数据失败！详见调试日志。", "提示",
                        MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        private bool SaveCalibData()
        {
            try
            {
                var paramList = IoC.Get<IParameterManager>() as IParamList;
                Directory.CreateDirectory(FileSaveDir);

                for (int i = 0; i < MotionCalibParItem.Count; i++)
                {
                    int areaIndex = i + 1;
                    var par = MotionCalibParItem[i];
                    var xmlPath = GetXmlPath(areaIndex);
                    var pointsPath = GetPointsPath(areaIndex);

                    // ① 保存 XML 参数
                    SaveXmlParam(paramList, xmlPath, par);

                    // ② 保存标定点位
                    if (HasCalibPoints(par))
                    {
                        MotionCalibFileService.SaveCalibPointsFile(
                            pointsPath, par.ResultRealPoints, par.ResultAxisPoints);
                    }
                }

                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"[MotionMenuCalib] SaveCalibData 失败: {ex}");
                return false;
            }
        }

        private void SaveXmlParam(IParamList paramList, string xmlPath, MotionSysDataItem par)
        {
            var uiData = UIDataManager.Instance.GetUIData<MotionSysData>(paramList);

            // 文件已存在 → 先读取保留完整结构，再回写
            if (File.Exists(xmlPath))
                uiData.Read(xmlPath);

            if (uiData.Datas == null)
                uiData.Datas = new List<MotionSysDataItem>();

            MotionSysDataItem item;
            if (uiData.Datas.Count > 0)
            {
                item = uiData.Datas[0];
            }
            else
            {
                item = new MotionSysDataItem { Id = par.Id, CameraId = par.CameraId };
                uiData.Datas.Add(item);
            }

            CopyParamFields(par, item);

            uiData.IsManualCreated = true;
            uiData.Write(xmlPath);
        }

        #endregion

        #region 读取数据

        public void btnReadCalibData()
        {
            var result = MwMessageBox.Show("确认读取本地标定数据？", "确认读取",
                MessageBoxButton.YesNo, MessageBoxImage.Warning);

            if (result == MessageBoxResult.Yes)
            {
                if (!ReadCalibData())
                {
                    MwMessageBox.Show("读取本地标定数据失败！详见调试日志。", "提示",
                        MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        public bool ReadCalibData()
        {
            try
            {
                var paramList = IoC.Get<IParameterManager>() as IParamList;
                var items = new ObservableCollection<MotionSysDataItem>();

                for (int i = 1; i <= CalibAreaCount; i++)
                {
                    var par = ReadSingleArea(paramList, i);
                    items.Add(par);
                }

                MotionCalibParItem = items;
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"[MotionMenuCalib] ReadCalibData 失败: {ex}");
                return false;
            }
        }

        private MotionSysDataItem ReadSingleArea(IParamList paramList, int areaIndex)
        {
            var xmlPath = GetXmlPath(areaIndex);
            var pointsPath = GetPointsPath(areaIndex);

            // 默认值
            double? startAxisX = 0, startAxisY = 0;
            double? startRealX = 0, startRealY = 0;
            int? rows = 0, columns = 0;
            double? rowStep = 0, columnStep = 0;
            List<Point> axisPoints = new List<Point>();
            List<Point> realPoints = new List<Point>();

            // ① 读 XML 参数
            if (File.Exists(xmlPath))
            {
                var uiData = UIDataManager.Instance.GetUIData<MotionSysData>(paramList);
                uiData.Read(xmlPath);

                if (uiData.Datas != null && uiData.Datas.Count > 0)
                {
                    var item = uiData.Datas[0];
                    startAxisX = item.StartAxisX;
                    startAxisY = item.StartAxisY;
                    startRealX = item.StartRealX;
                    startRealY = item.StartRealY;
                    rows = item.Rows;
                    columns = item.Columns;
                    rowStep = item.RowStep;
                    columnStep = item.ColumnStep;
                }
            }

            // ② 读标定点位
            if (File.Exists(pointsPath))
            {
                MotionCalibFileService.ReadCalibPointsFile(pointsPath, out realPoints, out axisPoints);
                axisPoints = axisPoints ?? new List<Point>();
                realPoints = realPoints ?? new List<Point>();
            }

            return new MotionSysDataItem
            {
                Id = areaIndex.ToString(),
                CameraId = Hardware[0].Camera.Id,
                CalibId = $"{AreaFilePrefix}{areaIndex}",
                StartAxisX = startAxisX,
                StartAxisY = startAxisY,
                StartRealX = startRealX,
                StartRealY = startRealY,
                Rows = rows,
                RowStep = rowStep,
                Columns = columns,
                ColumnStep = columnStep,
                ResultAxisPoints = axisPoints,
                ResultRealPoints = realPoints
            };
        }

        #endregion

        #region 应用数据

        public void btnApplyCalibData()
        {
            if (MotionCalibParItem.Count != CalibAreaCount)
            {
                MwMessageBox.Show("标定数据不足，请完成全部标定！", "提示",
                    MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            var result = MwMessageBox.Show("确认应用标定数据？", "确认应用",
                MessageBoxButton.YesNo, MessageBoxImage.Warning);

            if (result == MessageBoxResult.Yes)
            {
                if (ApplyCalibData())
                {
                    MwMessageBox.Show("应用标定数据成功！", "提示",
                        MessageBoxButton.OK, MessageBoxImage.Information);
                }
            }
        }

        private bool ApplyCalibData()
        {
            try
            {
                var cameraIdList = new List<string>();

                for (int i = 0; i < CalibAreaCount; i++)
                {
                    var par = MotionCalibParItem[i];
                    // Set 内部使用 1-based 区域编号
                    _motionFusion.Set(i + 1, par.ResultRealPoints, par.ResultAxisPoints);
                    cameraIdList.Add(par.CameraId);
                }

                // AutoSelectPt 需要 4 个 CameraId（四象限融合）
                _motionFusion.AutoSelectPt(
                    cameraIdList[0], cameraIdList[1],
                    cameraIdList[2], cameraIdList[3],
                    out _calibResultAxisPoint, out _calibResultRealPoint);

                MwAlgorithmHelper.Instance.RulerToRealMaritex(
                    Hardware[0].Camera.Id,
                    _calibResultAxisPoint, _calibResultRealPoint,
                    1, 1, 1, 1,
                    UIDataManager.CalibDataDir);

                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"[MotionMenuCalib] ApplyCalibData 失败: {ex}");
                MwMessageBox.Show($"应用失败：{ex.Message}", "错误",
                    MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
        }

        #endregion

        #region 公共辅助

        /// <summary>
        /// 将 source 的参数字段拷贝到 target（不包含 ResultRealPoints / ResultAxisPoints）
        /// </summary>
        private static void CopyParamFields(MotionSysDataItem source, MotionSysDataItem target)
        {
            target.StartAxisX = source.StartAxisX;
            target.StartAxisY = source.StartAxisY;
            target.StartRealX = source.StartRealX;
            target.StartRealY = source.StartRealY;
            target.Rows = source.Rows;
            target.RowStep = source.RowStep;
            target.Columns = source.Columns;
            target.ColumnStep = source.ColumnStep;
            target.XDirSpace = source.XDirSpace;
            target.CameraZPos = source.CameraZPos;
            target.Threshold = source.Threshold;
        }

        private static bool HasCalibPoints(MotionSysDataItem par) =>
            par.ResultRealPoints != null && par.ResultRealPoints.Count > 0 &&
            par.ResultAxisPoints != null && par.ResultAxisPoints.Count > 0;

        #endregion

        #region 窗口生命周期

        /// <summary>
        /// 主页面卸载时彻底关闭所有缓存窗口
        /// </summary>
        public void CleanupCalibWindows()
        {
            // 先标记所有需要强制关闭的 calibId
            foreach (var kvp in _calibWindows)
                _forceCloseIds.Add(kvp.Key);

            // 逐个关闭
            foreach (var kvp in _calibWindows)
            {
                try
                {
                    kvp.Value.Close();
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(
                        $"[MotionMenuCalib] 关闭窗口 {kvp.Key} 失败: {ex.Message}");
                }
            }

            _calibWindows.Clear();
            _forceCloseIds.Clear();
        }

        #endregion
    }
}
