using Logger;
using OxyPlot;
using OxyPlot.Annotations;
using OxyPlot.Axes;
using OxyPlot.Legends;
using OxyPlot.Series;
using Prism.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Input;
using CurveModule.ViewModels.Dialogs;
using UIShare.ViewModelBase;
using UIShare.GlobalVariable;

namespace CurveModule.ViewModels
{
    /// <summary>
    /// 曲线回读：加载 RecordView 导出的 CSV 文件，按 (MonitorName, Scope) 分组绘制曲线。
    /// </summary>
    public class CurveRecallViewModel : NavigateViewModelBase, IRegionMemberLifetime, IDisposable
    {
        #region 私有字段
        private GlobalConfig _globalConfig;
        #endregion
        #region 属性
        public bool KeepAlive => true;

        public PlotModel Plot { get; }

        /// <summary>已加载的曲线通道列表</summary>
        public ObservableCollection<CurveRecallChannelVM> Channels { get; } = new();

        private CurveRecallChannelVM? _selectedChannel;
        public CurveRecallChannelVM? SelectedChannel
        {
            get => _selectedChannel;
            set => SetProperty(ref _selectedChannel, value);
        }

        private string _statusMessage = "请加载 CSV 文件以回读曲线";
        public string StatusMessage
        {
            get => _statusMessage;
            set => SetProperty(ref _statusMessage, value);
        }
        #endregion

        #region 命令
        public ICommand LoadCsvCommand { get; }
        public ICommand ResetViewCommand { get; }
        public ICommand ClearCommand { get; }
        public ICommand StatisticsCommand { get; }
        public ICommand SaveCommand { get; }
        public ICommand LoadCommand { get; }
        public ICommand CaptureCommand { get; }

        #endregion

        #region 私有字段
        // 颜色调色盘（与 MonitorView 一致）
        private static readonly OxyColor[] _palette =
        {
            OxyColors.SteelBlue, OxyColors.IndianRed, OxyColors.SeaGreen,
            OxyColors.DarkOrange, OxyColors.MediumPurple, OxyColors.Goldenrod,
            OxyColors.Teal, OxyColors.Crimson, OxyColors.OliveDrab
        };
        private int _colorIndex;

        // 双光标截取
        private LineAnnotation? _cursor1;
        private LineAnnotation? _cursor2;
        private LineAnnotation? _draggingCursor;
        private List<MonitorRecord> _allRecords = new();
        #endregion

        /// <summary>截取按钮文本（随状态切换）</summary>
        private string _captureButtonText = "开始截取图形";
        public string CaptureButtonText
        {
            get => _captureButtonText;
            set => SetProperty(ref _captureButtonText, value);
        }

        public CurveRecallViewModel(IContainerProvider containerProvider) : base(containerProvider)
        {
            _globalConfig = containerProvider.Resolve<GlobalConfig>();
            Plot = BuildEmptyPlot();
            LoadCsvCommand = new DelegateCommand<string>(OnLoadCsv);
            ResetViewCommand = new DelegateCommand(OnResetView);
            ClearCommand = new DelegateCommand(OnClear);
            StatisticsCommand = new DelegateCommand(OnStatistics);
            SaveCommand = new DelegateCommand(OnSave);
            LoadCommand = new DelegateCommand(Onload);
            CaptureCommand = new DelegateCommand(OnToggleCapture);
        }


        #region 命令处理
        private void OnSave()
        {
            ConfigService.SaveGlobalConfig(_globalConfig);
        }
        private void Onload()
        {
            if (File.Exists(_globalConfig.DefaultCSVFilePath))
            {
                OnLoadCsv(_globalConfig.DefaultCSVFilePath);
            }
        }
        /// <summary>
        /// 打开 CSV 文件对话框，解析数据并按 (MonitorName, Scope) 分组绘制曲线。
        /// </summary>

        private void OnLoadCsv(string filename)
        {
            try
            {
                // 1. 统一处理 filename
                if (string.IsNullOrEmpty(filename))
                {
                    var dlg = new Microsoft.Win32.OpenFileDialog
                    {
                        Filter = "CSV 文件 (*.csv)|*.csv|所有文件|*.*",
                        Title = "选择要加载的监测数据 CSV 文件"
                    };

                    if (dlg.ShowDialog() != true)
                        return;

                    // 将弹窗选中的路径统一赋给 filename
                    filename = dlg.FileName;
                    _globalConfig.DefaultCSVFilePath = filename;
                }

                // 2. 统一解析数据
                List<MonitorRecord> records = ParseCsv(filename);
                _allRecords = records;

                if (records.Count == 0)
                {
                    StatusMessage = "CSV 文件为空或格式不正确";
                    return;
                }

                // 3. 按 (MonitorName, Scope) 分组
                var groups = records.GroupBy(r => (r.MonitorName, r.Scope))
                                    .OrderBy(g => g.Key.MonitorName)
                                    .ThenBy(g => g.Key.Scope);

                // 清空旧数据
                ClearPlotAndChannels();

                foreach (var group in groups)
                {
                    var color = _palette[_colorIndex % _palette.Length];
                    _colorIndex++;

                    string displayName = string.IsNullOrEmpty(group.Key.Scope)
                        ? group.Key.MonitorName
                        : $"{group.Key.MonitorName} [{group.Key.Scope}]";

                    var channel = new CurveRecallChannelVM
                    {
                        MonitorName = group.Key.MonitorName,
                        Scope = group.Key.Scope,
                        DisplayName = displayName,
                        Color = color,
                        IsDisplayed = true
                    };

                    // 创建 LineSeries 并填充数据点
                    channel.Series = new LineSeries
                    {
                        Title = displayName,
                        Color = color,
                        StrokeThickness = 1.5
                    };

                    // 按时间排序
                    var sortedPoints = group.OrderBy(r => r.CreateTime);
                    foreach (var point in sortedPoints)
                    {
                        channel.Series.Points.Add(new DataPoint(point.CreateTime.ToOADate(), point.MonitorValue));
                    }

                    channel.PropertyChanged += OnChannelPropertyChanged;

                    Plot.Series.Add(channel.Series);
                    Channels.Add(channel);
                }

                Plot.InvalidatePlot(true);

                // 4. 统一使用 filename 变量进行日志和状态更新
                StatusMessage = $"已加载 {Path.GetFileName(filename)}，共 {Channels.Count} 条曲线，{records.Count} 个数据点";
                LoggerHelper.Info($"曲线回读：加载 {filename}，{Channels.Count} 条曲线，{records.Count} 个数据点");
            }
            catch (Exception ex)
            {
                LoggerHelper.Error($"加载 CSV 失败：{ex.Message}");
                StatusMessage = $"加载失败：{ex.Message}";
            }
        }

        private void OnResetView()
        {
            Plot.ResetAllAxes();
            Plot.InvalidatePlot(false);
            StatusMessage = "视图已复原";
        }

        private void OnClear()
        {
            RemoveCursors();
            CaptureButtonText = "开始截取图形";
            ClearPlotAndChannels();
            _allRecords.Clear();
            Plot.InvalidatePlot(true);
            StatusMessage = "已清空，请重新加载 CSV 文件";
        }

        /// <summary>
        /// 对每条曲线计算数学统计（最大、最小、平均、斜率、积分），弹窗显示。
        /// </summary>
        private void OnStatistics()
        {
            if (Channels.Count == 0)
            {
                ShowInfoMessageBox("请先加载 CSV 文件", () => { });
                return;
            }

            var results = new ObservableCollection<CurveStatisticsResult>();
            foreach (var channel in Channels)
            {
                if (channel.Series == null || channel.Series.Points.Count == 0) continue;
                results.Add(ComputeStatistics(channel));
            }

            if (results.Count == 0)
            {
                ShowInfoMessageBox("没有可统计的曲线数据", () => { });
                return;
            }

            var parameters = new DialogParameters();
            parameters.Add("Results", results);
            _dialogService.ShowDialog("CurveStatistics", parameters, _ => { });
            StatusMessage = $"已计算 {results.Count} 条曲线的数学统计";
        }
        #endregion

        #region CSV 解析
        /// <summary>
        /// 解析 RecordView 导出的 CSV 文件，返回监测记录列表。
        /// </summary>
        private static List<MonitorRecord> ParseCsv(string path)
        {
            var results = new List<MonitorRecord>();

            using var sr = new StreamReader(path, Encoding.UTF8);

            // 读取表头
            string? headerLine = sr.ReadLine();
            if (headerLine == null) return results;

            var headers = ParseCsvLine(headerLine);
            int monitorNameIdx = headers.FindIndex(h => h.Trim() == "MonitorName");
            int monitorValueIdx = headers.FindIndex(h => h.Trim() == "MonitorValue");
            int scopeIdx = headers.FindIndex(h => h.Trim() == "Scope");
            int createTimeIdx = headers.FindIndex(h => h.Trim() == "CreateTime");

            if (monitorNameIdx < 0 || monitorValueIdx < 0 || scopeIdx < 0 || createTimeIdx < 0)
                return results;

            int maxIdx = Math.Max(monitorNameIdx, Math.Max(monitorValueIdx, Math.Max(scopeIdx, createTimeIdx)));

            string? line;
            while ((line = sr.ReadLine()) != null)
            {
                if (string.IsNullOrWhiteSpace(line)) continue;
                var fields = ParseCsvLine(line);
                if (fields.Count <= maxIdx) continue;

                if (!double.TryParse(fields[monitorValueIdx].Trim(), out double value)) continue;
                if (!DateTime.TryParse(fields[createTimeIdx].Trim(), out DateTime createTime)) continue;

                results.Add(new MonitorRecord
                {
                    MonitorName = fields[monitorNameIdx].Trim(),
                    MonitorValue = value,
                    Scope = fields[scopeIdx].Trim(),
                    CreateTime = createTime
                });
            }

            return results;
        }

        /// <summary>
        /// 解析单行 CSV，正确处理引号转义。
        /// </summary>
        private static List<string> ParseCsvLine(string line)
        {
            var fields = new List<string>();
            bool inQuotes = false;
            var sb = new StringBuilder();

            for (int i = 0; i < line.Length; i++)
            {
                char c = line[i];
                if (inQuotes)
                {
                    if (c == '"')
                    {
                        if (i + 1 < line.Length && line[i + 1] == '"')
                        {
                            sb.Append('"');
                            i++;
                        }
                        else
                        {
                            inQuotes = false;
                        }
                    }
                    else
                    {
                        sb.Append(c);
                    }
                }
                else
                {
                    if (c == '"')
                    {
                        inQuotes = true;
                    }
                    else if (c == ',')
                    {
                        fields.Add(sb.ToString());
                        sb.Clear();
                    }
                    else
                    {
                        sb.Append(c);
                    }
                }
            }

            fields.Add(sb.ToString());
            return fields;
        }
        #endregion

        #region OxyPlot 构建
        /// <summary>
        /// 构建空的 OxyPlot 模型（与 MonitorView 完全一致的配置）。
        /// </summary>
        private static PlotModel BuildEmptyPlot()
        {
            var pm = new PlotModel
            {
                Title = "曲线回读",
                PlotAreaBorderColor = OxyColors.LightGray,
                Background = OxyColors.White
            };
            pm.Axes.Add(new DateTimeAxis
            {
                Position = AxisPosition.Bottom,
                Title = "时间",
                StringFormat = "HH:mm:ss",
                MajorGridlineStyle = LineStyle.Dot,
                MinorGridlineStyle = LineStyle.None
            });
            pm.Axes.Add(new LinearAxis
            {
                Position = AxisPosition.Left,
                Title = "值",
                MajorGridlineStyle = LineStyle.Dot,
                MinorGridlineStyle = LineStyle.None
            });
            pm.Legends.Add(new Legend
            {
                LegendPosition = LegendPosition.RightTop,
                LegendBackground = OxyColor.FromAColor(200, OxyColors.White),
                LegendBorder = OxyColors.LightGray
            });
            return pm;
        }
        #endregion

        #region 辅助方法
        /// <summary>
        /// 对单条曲线计算数学统计：最大值、最小值、平均值、线性回归斜率、梯形积分。
        /// 斜率单位：值/秒；积分单位：值×秒。
        /// </summary>
        private static CurveStatisticsResult ComputeStatistics(CurveRecallChannelVM channel)
        {
            var points = channel.Series!.Points;
            int n = points.Count;

            if (n == 0)
                return new CurveStatisticsResult
                {
                    DisplayName = channel.DisplayName,
                    PointCount = 0
                };

            double max = double.MinValue;
            double min = double.MaxValue;
            double sumY = 0;

            // 线性回归累计量
            double sumX = 0, sumXY = 0, sumX2 = 0;

            // 梯形积分累计量
            double integral = 0;

            for (int i = 0; i < n; i++)
            {
                double x = points[i].X; // OADate 天数
                double y = points[i].Y;

                if (y > max) max = y;
                if (y < min) min = y;
                sumY += y;

                sumX += x;
                sumXY += x * y;
                sumX2 += x * x;

                if (i > 0)
                {
                    double dx = x - points[i - 1].X;
                    integral += dx * (y + points[i - 1].Y) / 2.0;
                }
            }

            double average = sumY / n;

            // 线性回归斜率（单位：值 / OADate 天）
            double slopePerDay = 0;
            double denominator = n * sumX2 - sumX * sumX;
            if (Math.Abs(denominator) > 1e-30)
            {
                slopePerDay = (n * sumXY - sumX * sumY) / denominator;
            }
            // 转换为 值/秒
            double slopePerSecond = slopePerDay / 86400.0;

            // 积分从 OADate·值 转换为 秒·值
            double integralSeconds = integral * 86400.0;

            return new CurveStatisticsResult
            {
                DisplayName = channel.DisplayName,
                PointCount = n,
                Max = max,
                Min = min,
                Average = average,
                Slope = slopePerSecond,
                Integral = integralSeconds
            };
        }

        private void OnChannelPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName != nameof(CurveRecallChannelVM.IsDisplayed)) return;
            if (sender is not CurveRecallChannelVM channel) return;

            if (channel.IsDisplayed)
            {
                if (channel.Series != null && !Plot.Series.Contains(channel.Series))
                {
                    Plot.Series.Add(channel.Series);
                }
            }
            else
            {
                if (channel.Series != null)
                {
                    Plot.Series.Remove(channel.Series);
                }
            }
            Plot.InvalidatePlot(true);
        }

        private void ClearPlotAndChannels()
        {
            foreach (var ch in Channels)
            {
                ch.PropertyChanged -= OnChannelPropertyChanged;
            }
            Plot.Series.Clear();
            Channels.Clear();
            _colorIndex = 0;
        }

        #endregion

        #region 双光标截取
        /// <summary>
        /// 切换截取模式：添加/移除双光标，结束时导出选中范围 CSV。
        /// </summary>
        private void OnToggleCapture()
        {
            if (_cursor1 == null)
            {
                CreateCursors();
                CaptureButtonText = "结束截取图形";
            }
            else
            {
                double x1 = _cursor1.X;
                double x2 = _cursor2!.X;
                double minX = Math.Min(x1, x2);
                double maxX = Math.Max(x1, x2);

                RemoveCursors();
                CaptureButtonText = "开始截取图形";

                ExportCapturedCsv(minX, maxX);
            }
        }

        /// <summary>
        /// 在图表上添加两条可拖拽的竖直光标。
        /// </summary>
        private void CreateCursors()
        {
            if (Channels.Count == 0) return;

            var dateAxis = Plot.Axes.OfType<DateTimeAxis>().FirstOrDefault();
            if (dateAxis == null) return;

            double xMin = dateAxis.ActualMinimum;
            double xMax = dateAxis.ActualMaximum;
            double range = xMax - xMin;
            if (range <= 0) return;

            _cursor1 = new LineAnnotation
            {
                Type = LineAnnotationType.Vertical,
                X = xMin + range * 0.3,
                Color = OxyColors.SteelBlue,
                StrokeThickness = 2,
                LineStyle = LineStyle.Dash,
                Text = "▼",
                TextColor = OxyColors.SteelBlue,
                TextHorizontalAlignment = HorizontalAlignment.Center,
                TextVerticalAlignment = VerticalAlignment.Top
            };

            _cursor2 = new LineAnnotation
            {
                Type = LineAnnotationType.Vertical,
                X = xMin + range * 0.7,
                Color = OxyColors.SteelBlue,
                StrokeThickness = 2,
                LineStyle = LineStyle.Dash,
                Text = "▼",
                TextColor = OxyColors.SteelBlue,
                TextHorizontalAlignment = HorizontalAlignment.Center,
                TextVerticalAlignment = VerticalAlignment.Top
            };

            _cursor1.MouseDown += OnCursorMouseDown;
            _cursor1.MouseUp += OnCursorMouseUp;
            _cursor2.MouseDown += OnCursorMouseDown;
            _cursor2.MouseUp += OnCursorMouseUp;
            Plot.MouseDown += OnPlotMouseMove;

            Plot.Annotations.Add(_cursor1);
            Plot.Annotations.Add(_cursor2);
            Plot.InvalidatePlot(true);
            StatusMessage = "已添加双光标，拖拽竖线选择范围，完成后点击「结束截取图形」";
        }

        /// <summary>
        /// 移除双光标并清理事件。
        /// </summary>
        private void RemoveCursors()
        {
            if (_cursor1 != null)
            {
                _cursor1.MouseDown -= OnCursorMouseDown;
                _cursor1.MouseUp -= OnCursorMouseUp;
                Plot.Annotations.Remove(_cursor1);
                _cursor1 = null;
            }
            if (_cursor2 != null)
            {
                _cursor2.MouseDown -= OnCursorMouseDown;
                _cursor2.MouseUp -= OnCursorMouseUp;
                Plot.Annotations.Remove(_cursor2);
                _cursor2 = null;
            }
            Plot.MouseDown -= OnPlotMouseMove;
            _draggingCursor = null;
            Plot.InvalidatePlot(true);
        }

        private void OnCursorMouseDown(object sender, OxyMouseDownEventArgs e)
        {
            if (sender is LineAnnotation line)
                _draggingCursor = line;
        }

        private void OnCursorMouseUp(object sender, OxyMouseEventArgs e)
        {
            _draggingCursor = null;
        }

        private void OnPlotMouseMove(object sender, OxyMouseDownEventArgs e)
        {
            if (_draggingCursor == null) return;

            var position = ((OxyMouseEventArgs)e).Position;
            var axis = Plot.Axes.OfType<DateTimeAxis>().FirstOrDefault();
            if (axis == null) return;

            double dataX = axis.InverseTransform(position.X, position.Y, null).X;

            // 限制光标不超出数据范围
            double xMin = axis.ActualMinimum;
            double xMax = axis.ActualMaximum;
            dataX = Math.Max(xMin, Math.Min(xMax, dataX));

            _draggingCursor.X = dataX;
            _draggingCursor.Text = $"▼ {DateTime.FromOADate(dataX):HH:mm:ss}";

            Plot.InvalidatePlot(true);
        }

        /// <summary>
        /// 导出双光标选定时间范围内的原始记录到 CSV。
        /// </summary>
        private void ExportCapturedCsv(double minXOaDate, double maxXOaDate)
        {
            if (_allRecords.Count == 0)
            {
                ShowInfoMessageBox("没有加载数据，无法导出", () => { });
                return;
            }

            var startTime = DateTime.FromOADate(minXOaDate);
            var endTime = DateTime.FromOADate(maxXOaDate);

            var filtered = _allRecords
                .Where(r => r.CreateTime >= startTime && r.CreateTime <= endTime)
                .OrderBy(r => r.CreateTime)
                .ToList();

            if (filtered.Count == 0)
            {
                ShowInfoMessageBox("选定范围内没有数据", () => { });
                return;
            }

            var dlg = new Microsoft.Win32.SaveFileDialog
            {
                Filter = "CSV 文件 (*.csv)|*.csv",
                Title = "导出截取范围数据",
                FileName = $"captured_{DateTime.Now:yyyyMMdd_HHmmss}.csv"
            };
            if (dlg.ShowDialog() != true) return;

            using var sw = new StreamWriter(dlg.FileName, false, Encoding.UTF8);
            sw.WriteLine("MonitorName,MonitorValue,Scope,CreateTime");
            foreach (var r in filtered)
            {
                sw.WriteLine($"{EscapeCsvField(r.MonitorName)},{r.MonitorValue},{EscapeCsvField(r.Scope)},{r.CreateTime:yyyy-MM-dd HH:mm:ss.fff}");
            }

            StatusMessage = $"已导出 {filtered.Count} 条记录到 {Path.GetFileName(dlg.FileName)}";
            LoggerHelper.Info($"导出截取范围 CSV：{dlg.FileName}，{filtered.Count} 条记录");
        }

        private static string EscapeCsvField(string field)
        {
            if (string.IsNullOrEmpty(field)) return "";
            if (field.Contains(',') || field.Contains('"') || field.Contains('\n'))
                return $"\"{field.Replace("\"", "\"\"")}\"";
            return field;
        }
        #endregion

        #region 生命周期
        public override void OnNavigatedTo(NavigationContext navigationContext)
        {
        }

        public void Dispose()
        {
            RemoveCursors();
            ClearPlotAndChannels();
        }
        #endregion
    }

    /// <summary>
    /// CSV 监测记录（单行数据）。
    /// </summary>
    internal class MonitorRecord
    {
        public string MonitorName { get; set; } = string.Empty;
        public double MonitorValue { get; set; }
        public string Scope { get; set; } = string.Empty;
        public DateTime CreateTime { get; set; }
    }

    /// <summary>
    /// 曲线回读通道：MonitorName + Scope 唯一标识一条曲线。
    /// </summary>
    public class CurveRecallChannelVM : Prism.Mvvm.BindableBase
    {
        public string MonitorName { get; set; } = string.Empty;
        public string Scope { get; set; } = string.Empty;
        public string DisplayName { get; set; } = string.Empty;
        public OxyColor Color { get; set; } = OxyColors.SteelBlue;

        private bool _isDisplayed = true;
        public bool IsDisplayed
        {
            get => _isDisplayed;
            set => SetProperty(ref _isDisplayed, value);
        }

        public LineSeries? Series { get; set; }
    }
}
