using OxyPlot.Series;
using OxyPlot;
using System;
using System.Collections.Concurrent;
using Prism.Mvvm;
using NCalc;

namespace UIShare.UIViewModel
{
    /// <summary>
    /// 监测通道：一个设备方法对应一个通道。
    /// 数据记录（DataPoints）与图表显示（Series）完全分离：
    ///   - IsMonitored=true 时始终记录 DataPoints
    ///   - IsDisplayed=true 时才创建 LineSeries 并绘制
    /// </summary>
    public class MonitorChannelVM : BindableBase
    {
        // ===== 标识 =====
        public string DeviceName { get; init; } = string.Empty;
        /// <summary>硬件指纹（物理设备唯一标识，用于匹配广播事件）</summary>
        public string Fingerprint { get; init; } = string.Empty;
        public string MethodName { get; init; } = string.Empty;
        public string DisplayName { get; init; } = string.Empty;

        // ===== 状态 =====
        private bool _isMonitored = true;
        /// <summary>是否在记录数据点（添加后始终为 true）</summary>
        public bool IsMonitored
        {
            get => _isMonitored;
            set => SetProperty(ref _isMonitored, value);
        }

        private bool _isDisplayed = true;
        /// <summary>是否在 OxyPlot 上显示</summary>
        public bool IsDisplayed
        {
            get => _isDisplayed;
            set => SetProperty(ref _isDisplayed, value);
        }

        // ===== 数学变换 =====
        private string? _mathExpression;
        /// <summary>可选数学变换表达式，如 "x*0.001"。为空则 DisplayValue=RawValue</summary>
        public string? MathExpression
        {
            get => _mathExpression;
            set => SetProperty(ref _mathExpression, value);
        }

        // ===== 颜色 =====
        public OxyColor Color { get; set; } = OxyColors.SteelBlue;

        // ===== 数据存储 =====
        /// <summary>所有采样数据点（线程安全），与 OxyPlot 无关</summary>
        public ConcurrentQueue<(DateTime Time, double RawValue, double DisplayValue)> DataPoints { get; } = new();

        /// <summary>最大缓冲数据点数，超出则丢弃最旧的</summary>
        public int MaxBuffer { get; set; } = 5000;

        // ===== OxyPlot Series（仅 IsDisplayed=true 时存在）=====
        private LineSeries? _series;
        public LineSeries? Series
        {
            get => _series;
            set => SetProperty(ref _series, value);
        }

        // ===== 辅助方法 =====
        /// <summary>记录一个数据点：RawValue 经数学变换后得到 DisplayValue，一并入队</summary>
        public void Record(DateTime time, double rawValue)
        {
            double displayValue = rawValue;

            DataPoints.Enqueue((time, rawValue, displayValue));

            // 超出缓冲上限时批量丢弃旧数据
            while (DataPoints.Count > MaxBuffer)
            {
                DataPoints.TryDequeue(out _);
            }

            // 如果正在显示，同步到 Series
            if (_series != null)
            {
                _series.Points.Add(new DataPoint(time.ToOADate(), displayValue));
                while (_series.Points.Count > 10000)
                {
                    _series.Points.RemoveAt(0);
                }
            }
        }
    }
}
