using ConfigOperator;
using HardwareData;
using HistoryUI.DataType;
using ScottPlot.Plottables;

namespace HistoryUI.ViewModels;

public partial class LogTraceViewModel : BaseViewModel<DBFormat>
{
    public LogTraceViewModel(Hardwares hardwares, IORM orm, BasicInfo basicInfo) : base(hardwares, orm)
    {
        this.Loading = Visibility.Collapsed;
        this.ChannelDetails = [];
        this.PlotControl = new();
        this.basicInfo = basicInfo;
        this.InitPlot();
    }

    private BasicInfo basicInfo;

    [ObservableProperty]
    private WpfPlot _PlotControl;
    [ObservableProperty]
    private string? _Hint;
    [ObservableProperty]
    private Visibility _Loading;

    private void InitPlot()
    {
        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.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:MM/dd HH:mm:ss}";
                ticks[i] = new Tick(ticks[i].Position, label);
            }
        };

        PixelPadding padding = new(40, 20, 65, 10);
        this.PlotControl.Plot.Layout.Fixed(padding);
        this.PlotControl.Plot.FigureBackground.Color = ScottPlot.Colors.Transparent;
        UpdateDetail();
    }

    private void UpdateDetail()
    {
        if (string.IsNullOrEmpty(basicInfo.DBConnectionString))
            return;
        if (base.Channels is null)
            return;

        if (!base.QueryBase(out byte mini8, out _))
            return;
        if (Mini8 != mini8)
        {
            this.ChannelDetails ??= [];
            this.ChannelDetails.Clear();
            foreach (var item in Channels)
            {
                IORM newOrm = new SqlSugarCustom();
                if (!newOrm.Initialize() || !newOrm.Open(basicInfo.DBConnectionString, ORM.DbType.PostgreSQL))
                    continue;
                if (string.IsNullOrEmpty(item.Value.Name) || item.Value.Name.StartsWith("Spare"))
                {
                    continue;
                }
                //Brush? brush;
                //try
                //{
                //    brush = (Brush)App.Current.Resources[$"PlotLine{item.Key}"];
                //}
                //catch
                //{
                //    brush = ChannelDetail.Default;
                //    throw;
                //}
                ChannelDetail detail = new()
                {
                    ChannelData = item.Value,
                    Orm = newOrm,
                    //ChannelColor = brush
                };

                this.ChannelDetails[item.Key] = detail;
            }

            Mini8 = mini8;
        }

    }

    [ObservableProperty]
    private ObservableDictionary<byte, ChannelDetail> _ChannelDetails;
    private byte Mini8;
    [RelayCommand]
    protected override void Query()
    {
        UpdateDetail();


        if (!base.QueryBase(out byte mini8, out _))
            return;
        this.Loading = Visibility.Visible;

        this.PlotControl.Plot.Clear();

        foreach (var channel in ChannelDetails)
        {
            if (channel.Value.Orm is null)
                continue;
            if (!channel.Value.IsSelected)
                continue;

            channel.Value.Orm.Query<DBFormat>($"Mini8-{mini8}-{channel.Key}",
            t =>
            t.DateTime >= this.StartTime &&
            t.DateTime <= this.EndTime
            , QueryResult);
        }
    }

    private void QueryResult(List<DBFormat> results)
    {
        if (results.Count < 1)
        {
            App.Current.Dispatcher.Invoke(() => this.Loading = Visibility.Collapsed);
            return;
        }

        List<DateTime> time = [];
        List<float> temp = [];
        results = [.. results.OrderBy(t => t.DateTime)];
        foreach (var item in results)
        {
            temp.Add(item.PV);
            time.Add(item.DateTime);
        }

        App.Current.Dispatcher.Invoke(() =>
        {
            this.SetLine(time, temp, LinePattern.Solid, MarkerStyle.None, 1f, out Brush brush);
            this.ChannelDetails[results.First().ChannelIndex].ChannelColor = brush;
            this.PlotControl.Plot.HideLegend();
            this.PlotControl.Plot.Axes.DateTimeTicksBottom();
            this.PlotControl.Plot.Axes.Bottom.TickLabelStyle.Rotation = -45;
            this.PlotControl.Plot.Axes.Bottom.TickLabelStyle.Alignment = Alignment.MiddleRight;
            this.PlotControl.Plot.Axes.AutoScale();
            this.PlotControl.Refresh();
            this.PlotControl.Plot.Axes.Zoom(1.085, 1);
            this.Loading = Visibility.Collapsed;
        });
    }

    private void SetLine(List<DateTime> time, List<float> value, LinePattern linePattern, MarkerStyle markerStyle, float lineWidth, out Brush brush)
    {
        Scatter mainScatter = this.PlotControl.Plot.Add.Scatter(time, value);
        mainScatter.MarkerStyle = markerStyle;
        mainScatter.LineWidth = lineWidth;
        mainScatter.LinePattern = linePattern;

        brush = new SolidColorBrush((System.Windows.Media.Color)ColorConverter.ConvertFromString(mainScatter.Color.ToStringRGB()));
    }

    [RelayCommand]
    private void ReScale(string para)
    {
        switch (para)
        {
            case "+":
                this.PlotControl.Plot.Axes.Zoom(1.25, 1);
                break;
            case "-":
                this.PlotControl.Plot.Axes.Zoom(0.8, 1);
                break;
            case "add":
                this.PlotControl.Plot.Axes.Zoom(1, 1.25);
                break;
            case "minus":
                this.PlotControl.Plot.Axes.Zoom(1, 0.8);
                break;

            default:
                this.PlotControl.Plot.Axes.AutoScale();
                this.PlotControl.Plot.Axes.Zoom(1.085, 1);
                break;
        }
        this.PlotControl.Refresh();
    }
}

public partial class ChannelDetail : ObservableObject
{
    public IORM? Orm;

    [ObservableProperty]
    private Brush _ChannelColor = Default;

    [ObservableProperty]
    private bool _IsSelected = false;

    private readonly static Brush Default = new SolidColorBrush((System.Windows.Media.Color)ColorConverter.ConvertFromString("#7f7f7f"));

    partial void OnIsSelectedChanged(bool value)
    {
        if (!IsSelected)
            this.ChannelColor = Default;
    }

    [ObservableProperty]
    private ChannelData? _ChannelData;
}
