using ScottPlot;
using ScottPlot.Plottables;
using ScottPlot.WPF;

namespace MinicsUI.Helper;

public partial class RealtimeDataPlotHelper : ObservableObject, IDisposable
{
    [ObservableProperty]
    private WpfPlot? _PlotControl;

    private bool _DisposedValue;
    private readonly List<float> _HistoryData = [];
    private readonly List<DateTime> _HistoryTime = [];

    public Channel? Channel { get; private set; }

    public void InitPlot(Channel channel)
    {
        if (channel is null)
            return;
        this.Channel = channel;
        this._HistoryData.Clear();
        this._HistoryTime.Clear();
        _HistoryData.AddRange(this.Channel.PVRingBuffer.ReadValues());
        _HistoryTime.AddRange(this.Channel.DateTimeRingBuffer.ReadValues());

        this.PlotControl = new();
        this.PlotControl.Plot.Grid.XAxisStyle.MajorLineStyle.Width = 1f;
        this.PlotControl.Plot.Grid.YAxisStyle.MajorLineStyle.Width = 1f;
        this.PlotControl.Plot.FigureBackground.Color = ScottPlot.Colors.Transparent;
        this.PlotControl.UserInputProcessor.Disable();

        this.PlotControl.Plot.RenderManager.RenderStarting += (s, e) =>
        {
            Tick[] ticks = this.PlotControl.Plot.Axes.Bottom.TickGenerator.Ticks;
            for (int i = 0; i < ticks.Length; i++)
            {
                DateTime dt = DateTime.FromOADate(ticks[i].Position);
                string label = $"{dt:HH:mm:ss}";
                ticks[i] = new Tick(ticks[i].Position, label);
            }
        };

        this.Channel.OnPVChangedEvent += OnPVChanged;
    }

    private void OnPVChanged(float pv, DateTime dateTime)
    {
        if (Channel is null)
            return;

        if (this.PlotControl is null)
            return;

        switch (this._HistoryData.Count)
        {
            case >= 120:
                _HistoryTime.RemoveAt(0);
                _HistoryTime.Add(dateTime);

                _HistoryData.RemoveAt(0);
                _HistoryData.Add(pv);
                break;
            default:
                _HistoryData.Add(pv);
                _HistoryTime.Add(dateTime);
                break;
        }

        if (this.PlotControl is null)
            return;
        this.PlotControl.Plot.Clear();
        this.PlotControl.Plot.Add.HorizontalLine(this.Channel.Caps, 1f, ScottPlot.Color.FromHex("FF0000"), LinePattern.Dotted);
        this.PlotControl.Plot.Add.HorizontalLine(this.Channel.Floor, 1f, ScottPlot.Color.FromHex("FF0000"), LinePattern.Dotted);
        this.PlotControl.Plot.Add.HorizontalLine(this.Channel.CapsWarning, 1f, ScottPlot.Color.FromHex("FFA500"), LinePattern.Dotted);
        this.PlotControl.Plot.Add.HorizontalLine(this.Channel.FloorWarning, 1f, ScottPlot.Color.FromHex("FFA500"), LinePattern.Dotted);
        this.PlotControl.Plot.Add.HorizontalLine(this.Channel.SetPoint, 1f, ScottPlot.Color.FromHex("00FF00"), LinePattern.Dotted);
        Scatter mainScatter = this.PlotControl.Plot.Add.Scatter(_HistoryTime, _HistoryData, ScottPlot.Color.FromHex("0074c1"));
        mainScatter.MarkerStyle = MarkerStyle.None;
        mainScatter.LineWidth = 3f;
        this.PlotControl.Plot.Axes.DateTimeTicksBottom();
        this.PlotControl.Plot.Axes.AutoScale();
        this.PlotControl?.Refresh();

    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_DisposedValue)
        {
            if (disposing)
            {
                this.PlotControl = null;
            }

            if (this.Channel is not null)
                this.Channel.OnPVChangedEvent -= OnPVChanged;
            _DisposedValue = true;
        }
    }

    ~RealtimeDataPlotHelper()
    {
        Dispose(disposing: false);
    }

    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
}
