namespace HistoryView.ViewModels.Dialogs;

internal partial class ChannedDetailViewModel(Data.Hardwares hardwares, MessageBoxHelper messageBoxHelper, HubSender sender, HistoryViewer historyViewer, UserInformation user) : ObservableObject, IDialogAwareTitle
{
    public DialogCloseListener RequestClose { get; set; }
    public string Title { get; set; } = "Channel Setting";

    [ObservableProperty]
    private Mini8Info? _Mini8Info;

    [ObservableProperty]
    private Channel? _Channel;

    [ObservableProperty]
    private Channel? _ChannelSet;

    [ObservableProperty]
    private UserInformation? _UserInfo;

    [ObservableProperty]
    private ObservableCollection<string>? _BackWords;

    [ObservableProperty]
    private RealtimeDataPlotHelper? _PlotHelper;

    public bool CanCloseDialog() => true;

    public void OnDialogClosed()
    {
        this.PlotHelper?.Dispose();
        this.Mini8Info = null;
        this.Channel = null;
        this.ChannelSet = null;
        this.UserInfo = null;
        this.BackWords = null;
        this.PlotHelper = null;
    }

    public void OnDialogOpened(IDialogParameters parameters)
    {
        this.UserInfo = user;
        this.PlotHelper = new();
        if (parameters.TryGetValue("Channel", out Channel? channel) && channel is not null)
        {
            this.Channel = channel;
            this.PlotHelper.InitPlot(channel);
            this.BackWords ??= [];
            HashSet<string> hs = [];

            if (hardwares.Mini8s.TryGetValue(channel.Mini8Index, out Mini8Info? mini8Info) && mini8Info is not null)
                this.Mini8Info = mini8Info;

            foreach (Channel item in hardwares.Mini8Channels[channel.Mini8Index].Values)
            {
                if (item is null || string.IsNullOrEmpty(item.Name))
                    continue;
                hs.Add(item.Name);
            }
            this.BackWords.AddRange(hs);
        }

        this.ChannelSet = new();
        channel.Adapt(this.ChannelSet);

    }

    [RelayCommand]
    private async Task Operate(string para)
    {
        bool succcess = false;
        if (this.ChannelSet is null)
            goto Hint;

        if (this.Channel is not null &&
            this.Channel.Inhibit == Inhibit.Disable &&
            this.ChannelSet.Inhibit == Inhibit.Disable)
        {
            await messageBoxHelper.ShowAsync($"Inhibit Status: {this.Channel.Inhibit}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }

        if (ChannelSet.Caps < ChannelSet.CapsWarning ||
            ChannelSet.CapsWarning < ChannelSet.FloorWarning ||
            ChannelSet.FloorWarning < ChannelSet.Floor)
        {
            await messageBoxHelper.ShowAsync($"Please follow the rule:{Environment.NewLine} Caps > CapsWarning > FloorWarning > Floor", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }

        if (this.Channel is not null && this.Channel.ChannelMode != ChannelMode.Control)
        {
            await messageBoxHelper.ShowAsync($"Channel Mode: {this.Channel.ChannelMode}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }
        IDialogResult result = await messageBoxHelper.ShowAsync(Compare(), MessageBoxButton.OKCancel, MessageBoxImage.Question);

        if (result.Result != ButtonResult.OK)
            return;

        succcess = sender.SendSetValue(this.ChannelSet);
    Hint:
        if (!succcess)
            await messageBoxHelper.ShowAsync("Failed", MessageBoxButton.OK, MessageBoxImage.Error);
    }


    [RelayCommand]
    private async Task EnableAT()
    {
        if (this.Channel is null)
            return;
        if (this.Channel.Inhibit == Inhibit.Disable)
        {
            await messageBoxHelper.ShowAsync($"Inhibit Status: {this.Channel.Inhibit}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }

        if (this.Channel.ChannelMode != ChannelMode.Control)
        {
            await messageBoxHelper.ShowAsync($"Channel Mode: {this.Channel.ChannelMode}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }

        switch (this.Channel.AutoTuneStatus)
        {
            case AutoTuneStatus.Ready:
            case AutoTuneStatus.Complete:
            case AutoTuneStatus.Aborted:
            case AutoTuneStatus.Timeout:
            case AutoTuneStatus.Overflow:
            case AutoTuneStatus.Unavailable:
                break;
            case AutoTuneStatus.Triggered:
            case AutoTuneStatus.Tuning:
                await messageBoxHelper.ShowAsync($"AutoTune Status: {this.Channel.AutoTuneStatus}", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            default:
                break;
        }

        IDialogResult? result = await messageBoxHelper.ShowAsync((string)App.Current.Resources["SendParameter"], MessageBoxButton.OKCancel, MessageBoxImage.Question);

        if (result is null || result.Result != ButtonResult.OK)
            return;

        if (!sender.EnableAT(this.Channel.Mini8Index, this.Channel.ChannelIndex, true))
            await messageBoxHelper.ShowAsync("Failed", MessageBoxButton.OK, MessageBoxImage.Error);
    }

    [RelayCommand]
    private async Task AbortAT()
    {
        if (this.Channel is null)
            return;
        if (this.Channel.Inhibit == Inhibit.Disable)
        {
            await messageBoxHelper.ShowAsync($"Inhibit Status: {this.Channel.Inhibit}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }
        if (this.Channel.ChannelMode != ChannelMode.Control)
        {
            await messageBoxHelper.ShowAsync($"Channel Mode: {this.Channel.ChannelMode}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }

        IDialogResult? result = await messageBoxHelper.ShowAsync((string)App.Current.Resources["SendParameter"], MessageBoxButton.OKCancel, MessageBoxImage.Question);

        if (result is null || result.Result != ButtonResult.OK)
            return;

        if (!sender.EnableAT(this.Channel.Mini8Index, this.Channel.ChannelIndex, false))
            await messageBoxHelper.ShowAsync("Failed", MessageBoxButton.OK, MessageBoxImage.Error);
    }


    [RelayCommand]
    private async Task EnableChannel(string para)
    {
        if (this.Channel is null)
            return;

        if (string.IsNullOrEmpty(para))
            return;

        IDialogResult? result = await messageBoxHelper.ShowAsync((string)App.Current.Resources["SendParameter"], MessageBoxButton.OKCancel, MessageBoxImage.Question);
        if (result is null || result.Result != ButtonResult.OK)
            return;


        bool isSuccess = para switch
        {
            "Enable" => sender.EnableChannel(this.Channel.Mini8Index, this.Channel.ChannelIndex, Inhibit.Enable),
            "Disable" => sender.EnableChannel(this.Channel.Mini8Index, this.Channel.ChannelIndex, Inhibit.Disable),
            "Control" => sender.SwitchChannelMode(this.Channel.Mini8Index, this.Channel.ChannelIndex, ChannelMode.Control),
            "Monitor" => sender.SwitchChannelMode(this.Channel.Mini8Index, this.Channel.ChannelIndex, ChannelMode.Monitor),
            _ => false
        };

        if (!isSuccess)
            await messageBoxHelper.ShowAsync("Failed", MessageBoxButton.OK, MessageBoxImage.Error);
    }

    [RelayCommand]
    private async Task ApplyPID()
    {
        if (this.ChannelSet is null || this.Channel is null)
            return;

        if (this.Channel.Inhibit == Inhibit.Disable)
        {
            await messageBoxHelper.ShowAsync($"Inhibit Status: {this.Channel.Inhibit}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }
        if (this.Channel.ChannelMode != ChannelMode.Control)
        {
            await messageBoxHelper.ShowAsync($"Channel Mode: {this.Channel.ChannelMode}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }

        switch (this.Channel.AutoTuneStatus)
        {
            case AutoTuneStatus.Complete:
                break;
            case AutoTuneStatus.Ready:
            case AutoTuneStatus.Aborted:
            case AutoTuneStatus.Timeout:
            case AutoTuneStatus.Overflow:
            case AutoTuneStatus.Unavailable:
            case AutoTuneStatus.Triggered:
            case AutoTuneStatus.Tuning:
            default:
                await messageBoxHelper.ShowAsync($"AutoTune Status: {this.Channel.AutoTuneStatus}", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
        }

        this.ChannelSet.Running_P = this.Channel.AutoTune_P;
        this.ChannelSet.Running_I = this.Channel.AutoTune_I;
        this.ChannelSet.Running_D = this.Channel.AutoTune_D;

        IDialogResult? result = await messageBoxHelper.ShowAsync(Compare(), MessageBoxButton.OKCancel, MessageBoxImage.Question);

        if (result is null || result.Result != ButtonResult.OK)
            return;

        bool success = sender.SelectPID(this.Channel.Mini8Index, this.Channel.ChannelIndex, ActiveTuneSet.Running);
        success &= sender.SendSetValue(this.ChannelSet);

        if (!success)
            await messageBoxHelper.ShowAsync("Failed", MessageBoxButton.OK, MessageBoxImage.Error);
    }

    [RelayCommand]
    private async Task SelectPID(string para)
    {
        if (this.Channel is null)
            return;

        if (this.Channel.Inhibit == Inhibit.Disable)
        {
            await messageBoxHelper.ShowAsync($"Inhibit Status: {this.Channel.Inhibit}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }
        if (this.Channel.ChannelMode != ChannelMode.Control)
        {
            await messageBoxHelper.ShowAsync($"Channel Mode: {this.Channel.ChannelMode}", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }

        switch (this.Channel.AutoTuneStatus)
        {
            case AutoTuneStatus.Ready:
            case AutoTuneStatus.Complete:
            case AutoTuneStatus.Aborted:
            case AutoTuneStatus.Timeout:
            case AutoTuneStatus.Overflow:
            case AutoTuneStatus.Unavailable:
                break;
            case AutoTuneStatus.Triggered:
            case AutoTuneStatus.Tuning:
                await messageBoxHelper.ShowAsync($"AutoTune Status: {this.Channel.AutoTuneStatus}", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            default:
                break;
        }

        if (string.IsNullOrEmpty(para))
            return;

        IDialogResult? result = await messageBoxHelper.ShowAsync((string)App.Current.Resources["SendParameter"], MessageBoxButton.OKCancel, MessageBoxImage.Question);
        if (result is null || result.Result != ButtonResult.OK)
            return;

        bool isSuccess = para switch
        {
            "Running" => sender.SelectPID(this.Channel.Mini8Index, this.Channel.ChannelIndex, ActiveTuneSet.Running),
            "Autotune" => sender.SelectPID(this.Channel.Mini8Index, this.Channel.ChannelIndex, ActiveTuneSet.AutoTune),
            _ => false
        };

        if (!isSuccess)
            await messageBoxHelper.ShowAsync("Failed", MessageBoxButton.OK, MessageBoxImage.Error);
    }

    [RelayCommand]
    private void ViewHistory()
    {
        if (this.Channel is null)
            return;

        if (!historyViewer.StartChannelHistory(Channel.Mini8Index, Channel.ChannelIndex))
            return;
    }

    [RelayCommand]
    private void Exit() => this.RequestClose.Invoke();


    private string Compare()
    {
        if (this.ChannelSet is null || Channel is null)
            return string.Empty;

        StringBuilder sb = new();
        sb.AppendLine((string)App.Current.Resources["SendParameter"]);

        SBHelper("SetValue", Channel.SetPoint, ChannelSet.SetPoint, sb);
        SBHelper("Caps", Channel.Caps, ChannelSet.Caps, sb);
        SBHelper("Floor", Channel.Floor, ChannelSet.Floor, sb);
        SBHelper("CapsWarning", Channel.CapsWarning, ChannelSet.CapsWarning, sb);
        SBHelper("FloorWarning", Channel.FloorWarning, ChannelSet.FloorWarning, sb);
        SBHelper("Running_P", Channel.Running_P, ChannelSet.Running_P, sb);
        SBHelper("Running_I", Channel.Running_I, ChannelSet.Running_I, sb);
        SBHelper("Running_D", Channel.Running_D, ChannelSet.Running_D, sb);
        SBHelper("SetpointUpRate", Channel.SetpointUpRate, ChannelSet.SetpointUpRate, sb);
        SBHelper("SetpointDownRate", Channel.SetpointDownRate, ChannelSet.SetpointDownRate, sb);
        return sb.ToString();
    }
    private static void SBHelper<T>(string title, T oldValue, T newValue, StringBuilder sb) where T : IComparable
    {
        if (oldValue.CompareTo(newValue) != 0)
            sb.AppendLine($"{title.PadRight(20)} {oldValue.ToString()!.PadRight(6)} -->  {newValue}");
    }
}