using Logger;
using OxyPlot;
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 UIShare.ViewModelBase;

namespace CurveModule.ViewModels
{
    /// <summary>
    /// 曲线回读：加载 RecordView 导出的 CSV 文件，按 (MonitorName, Scope) 分组绘制曲线。
    /// </summary>
    public class CurveRecallViewModel : NavigateViewModelBase, IRegionMemberLifetime, IDisposable
    {
        #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; }
        #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;
        #endregion

        public CurveRecallViewModel(IContainerProvider containerProvider) : base(containerProvider)
        {
            Plot = BuildEmptyPlot();
            LoadCsvCommand = new DelegateCommand(OnLoadCsv);
            ResetViewCommand = new DelegateCommand(OnResetView);
            ClearCommand = new DelegateCommand(OnClear);
        }

        #region 命令处理
        /// <summary>
        /// 打开 CSV 文件对话框，解析数据并按 (MonitorName, Scope) 分组绘制曲线。
        /// </summary>
        private void OnLoadCsv()
        {
            try
            {
                var dlg = new Microsoft.Win32.OpenFileDialog
                {
                    Filter = "CSV 文件 (*.csv)|*.csv|所有文件|*.*",
                    Title = "选择要加载的监测数据 CSV 文件"
                };
                if (dlg.ShowDialog() != true) return;

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

                // 按 (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);
                StatusMessage = $"已加载 {Path.GetFileName(dlg.FileName)}，共 {Channels.Count} 条曲线，{records.Count} 个数据点";
                LoggerHelper.Info($"曲线回读：加载 {dlg.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()
        {
            ClearPlotAndChannels();
            Plot.InvalidatePlot(true);
            StatusMessage = "已清空，请重新加载 CSV 文件";
        }
        #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 辅助方法
        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 生命周期
        public override void OnNavigatedTo(NavigationContext navigationContext)
        {
        }

        public void Dispose()
        {
            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; }
    }
}
