using System.Net.WebSockets;

namespace MinicsUI.ViewModels.Dialogs;

public partial class ChannelMultiEditViewModel(Hardwares hardwares, MessageBoxHelper messageBoxHelper, HubSender sender) : ObservableObject, IDialogAwareTitle
{
    #region IDialogAwareTitle
    public string Title { get; set; } = "MultiEdit";

    DialogCloseListener IDialogAware.RequestClose { get; }

    bool IDialogAware.CanCloseDialog()
    {
        return true;
    }

    void IDialogAware.OnDialogClosed()
    {
    }

    void IDialogAware.OnDialogOpened(IDialogParameters parameters)
    {
        if (!parameters.TryGetValue("Mini8Info", out Mini8Info? mini8) || mini8 is null)
            return;

        if (!hardwares.Mini8Channels.TryGetValue(mini8.Index, out ObservableDictionary<byte, Channel>? channels) || channels is null)
            return;

        this.Channels = channels;
        this.Selecters ??= [];

        foreach (var item in channels.Values)
        {
            if (item.ChannelMode == ChannelMode.UnUsed)
                continue;

            switch (item.ChannelMode)
            {
                case ChannelMode.Control:
                case ChannelMode.Monitor:
                    this.Selecters.Add(new(item));
                    break;
                case ChannelMode.UnUsed:
                default:
                    break;
            }
        }
    }
    #endregion

    [ObservableProperty]
    private string? _Hint;

    [ObservableProperty]
    private Visibility _HintVis = Visibility.Collapsed;

    [ObservableProperty]
    private ObservableCollection<Selector> _Selecters = [];

    [ObservableProperty]
    private ObservableDictionary<byte, Channel> _Channels = [];



    [RelayCommand]
    private void Select(string para)
    {
        _ = para switch
        {
            "All" => this.Selecters.Foreach(t => t.IsSelected = true),
            "None" => this.Selecters.Foreach(t => t.IsSelected = false),
            _ => 0
        };
    }

    [RelayCommand]
    private void AutoTune()
    {
        List<Channel> channels = [];

        foreach (Selector selector in this.Selecters.Where(t => t.IsSelected))
        {
            Channel channel = selector.Channel;

            if (channel is null)
                return;

            if (channel.Inhibit == Inhibit.Disable)
            {
                messageBoxHelper.Show($"Channel {channel.Name} Inhibit Status: {channel.Inhibit}", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            if (channel.ChannelMode != ChannelMode.Control)
            {
                messageBoxHelper.Show($"Channel {channel.Name} Channel Mode: {channel.ChannelMode}", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

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

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

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

        this.HintVis = Visibility.Visible;
        Task.Factory.StartNew(() =>
       {
           foreach (Channel channel in channels)
           {
               this.Hint = $"Enable Channel {channel.Name} Autotune...";
               if (!sender.EnableAT(channel.Mini8Index, channel.ChannelIndex, true))
                   App.Current.Dispatcher.Invoke(() => { messageBoxHelper.ShowAsync($"{channel.Name} Failed", MessageBoxButton.OK, MessageBoxImage.Error).Wait(); });
               Thread.Sleep(200);
           }
           App.Current.Dispatcher.Invoke(() => { this.HintVis = Visibility.Collapsed; });
       });
    }

    [RelayCommand]
    private void AbortAutoTune()
    {
        this.HintVis = Visibility.Visible;
        Task.Factory.StartNew(() =>
        {
            foreach (Selector selector in this.Selecters.Where(t => t.IsSelected))
            {
                this.Hint = $"Abort Channel {selector.Channel.Name} Autotune...";

                Channel channel = selector.Channel;

                if (!sender.EnableAT(channel.Mini8Index, channel.ChannelIndex, false))
                    App.Current.Dispatcher.Invoke(() => { messageBoxHelper.ShowAsync($" {selector.Channel.Name} Failed", MessageBoxButton.OK, MessageBoxImage.Error).Wait(); });
                Thread.Sleep(200);
            }
            App.Current.Dispatcher.Invoke(() => { this.HintVis = Visibility.Collapsed; });
        });
    }

    [RelayCommand]
    private void ControlMode(string para)
    {
        this.HintVis = Visibility.Visible;
        Task.Factory.StartNew(() =>
        {
            IEnumerable<Selector> selectors = this.Selecters.Where(t => t.IsSelected);
            foreach (var selector in selectors)
            {
                this.Hint = $"Set Channel {selector.Channel.Name} {para}...";

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

                if (!isSuccess)
                    App.Current.Dispatcher.Invoke(() => { messageBoxHelper.ShowAsync($"{selector.Channel.Name} Failed", MessageBoxButton.OK, MessageBoxImage.Error).Wait(); });

                Thread.Sleep(200);
            }
            App.Current.Dispatcher.Invoke(() => { this.HintVis = Visibility.Collapsed; });
        });
    }

    [RelayCommand]
    private void ChannelModeSwitch(string para)
    {
        IDialogResult? result = messageBoxHelper.ShowAsync((string)App.Current.Resources["SendParameter"], MessageBoxButton.OKCancel, MessageBoxImage.Question).Result;

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

        IEnumerable<Selector> selectors = this.Selecters.Where(t => t.IsSelected);

        foreach (var selector in selectors)
        {
            bool isSuccess = para switch
            {
                "Control" => sender.SwitchChannelMode(selector.Channel.Mini8Index, selector.Channel.ChannelIndex, ChannelMode.Control),
                "Monitor" => sender.SwitchChannelMode(selector.Channel.Mini8Index, selector.Channel.ChannelIndex, ChannelMode.Monitor),
                _ => false
            };
        }
    }

    [RelayCommand]
    private void ApplyATPID()
    {
        IDialogResult? result = messageBoxHelper.ShowAsync((string)App.Current.Resources["SendParameter"], MessageBoxButton.OKCancel, MessageBoxImage.Question).Result;

        if (result is null || result.Result != ButtonResult.OK)
            return;
        this.HintVis = Visibility.Visible;
        IEnumerable<Selector> selectors = this.Selecters.Where(t => t.IsSelected);

        Task.Factory.StartNew(() =>
        {
            foreach (var selector in selectors)
            {
                Channel ChannelSet = new();
                selector.Channel.Adapt(ChannelSet);

                if (selector.Channel.Inhibit == Inhibit.Disable)
                {
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        messageBoxHelper.ShowAsync($"Channel {selector.Channel.Name} Inhibit Status: {selector.Channel.Inhibit}", MessageBoxButton.OK, MessageBoxImage.Error).Wait();
                    });
                    continue;
                }
                if (selector.Channel.ChannelMode != ChannelMode.Control)
                {
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        messageBoxHelper.ShowAsync($"Channel {selector.Channel.Name} Channel Mode: {selector.Channel.ChannelMode}", MessageBoxButton.OK, MessageBoxImage.Error).Wait();
                    });
                    continue;
                }

                switch (selector.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:
                        App.Current.Dispatcher.Invoke(() =>
                        {
                            messageBoxHelper.ShowAsync($"Channel {selector.Channel.Name} AutoTune Status: {selector.Channel.AutoTuneStatus}", MessageBoxButton.OK, MessageBoxImage.Error).Wait();
                        });
                        continue;
                }

                this.Hint = $"Channel {selector.Channel.Name}  Applying Autotune PID ...";

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

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

                if (!success)
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        messageBoxHelper.ShowAsync($"Channel {selector.Channel.Name} Failed", MessageBoxButton.OK, MessageBoxImage.Error).Wait();
                    });

                Thread.Sleep(300);
            }
            App.Current.Dispatcher.Invoke(() => { this.HintVis = Visibility.Collapsed; });

        });
    }

    [RelayCommand]
    private void Exit()
    {
        (this as IDialogAware).RequestClose.Invoke();
    }

}

public partial class Selector : ObservableObject
{
    public Selector(Channel channelName)
    {
        this.Channel = channelName;
    }

    [ObservableProperty]
    private Channel _Channel;

    [ObservableProperty]
    private bool _IsSelected;
}
