using MinicsUI.Helper;

namespace HistoryView.ViewModels.Regions;

internal partial class MonitorViewModel : ObservableObject
{
    public MonitorViewModel(IDialogService dialogService, Hardwares hardwares, HubSender sender, UserInformation userInformation, HistoryViewer historyViewer)
    {
        this._dialogService = dialogService;
        this.Hardwares = hardwares;
        LoadDisplayHardwares();
        _sender = sender;
        this.User = userInformation;
        _historyViewer = historyViewer;
    }

    private void LoadDisplayHardwares()
    {
        Mini8DisplayStatus ??= [];
        Mini8DisplayStatus.Clear();
        foreach (KeyValuePair<byte, Mini8Info> mini8Pair in Hardwares.Mini8s)
        {
            Mini8DisplayStatus!.Add(mini8Pair.Value, new(true));
            DisplayMini8[mini8Pair.Value] = [];
            DisplayMini8[mini8Pair.Value].AddRange(Hardwares.Mini8Channels[mini8Pair.Key].Values);
        }
    }

    private readonly IDialogService _dialogService;
    private readonly HubSender _sender;
    private readonly HistoryViewer _historyViewer;

    [ObservableProperty]
    private UserInformation _User;

    [ObservableProperty]
    private ObservableDictionary<Mini8Info, DisplayDetail>? _Mini8DisplayStatus = [];

    [ObservableProperty]
    private ObservableDictionary<Mini8Info, ObservableCollection<Channel>> _DisplayMini8 = [];

    [ObservableProperty]
    private Hardwares _hardwares;

    [ObservableProperty]
    private int _Rows = 4;

    [RelayCommand]
    private void EditChannel(Channel channel)
    {

        switch (channel.ChannelMode)
        {
            case ChannelMode.Control:
            case ChannelMode.Monitor:
                break;
            case ChannelMode.UnUsed:
            default:
                return;
        }

        DialogParameters para = new()
        {
            { "Channel", channel },
        };

        this._dialogService.Show("Channel", para, null);
    }

    [RelayCommand]
    private void MultiSelect(Mini8Info mini8Info)
    {
        DialogParameters para = new()
        {
            { "Mini8Info", mini8Info },
            //{ "ChannelSetValue", channelSetValue },
        };

        this._dialogService.Show("MultiEdit", para, null);
    }

    [RelayCommand]
    private void ViewMultiTrace(Mini8Info mini8Info)
    {
        if (!this._historyViewer.StartMultiChannelHistory(mini8Info.Index))
            return;
    }

    [RelayCommand]
    private void TraceLog(Mini8Info mini8Info)
    {
        DialogParameters para = new()
        {
            { "Mini8Info", mini8Info },
            //{ "ChannelSetValue", channelSetValue },
        };

        this._dialogService.Show("TraceLog", para, null);
    }

    [RelayCommand]
    private void Display(KeyValuePair<Mini8Info, DisplayDetail> displayInfo)
    {
        Task.Factory.StartNew(() =>
        {
            if (!displayInfo.Value.IsDisplay)
            {
                App.Current.Dispatcher.Invoke(() =>
                {
                    this.DisplayMini8.Remove(displayInfo.Key);
                });
            }
            else
            {
                if (this.DisplayMini8.ContainsKey(displayInfo.Key))
                    return;

                foreach (var channels in this.Hardwares.Mini8Channels)
                {
                    if (channels.Value is null)
                        continue;

                    if (channels.Key != displayInfo.Key.Index)
                        continue;

                    if (!this.Hardwares.Mini8s.TryGetValue(channels.Key, out Mini8Info? mini8Info) || mini8Info is null)
                        continue;
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        this.DisplayMini8[displayInfo.Key] ??= [];
                        this.DisplayMini8[displayInfo.Key].AddRange(channels.Value.Values);
                    });
                }
            }
        });
    }

    [RelayCommand]
    private void DisplayAll(string para)
    {
        Task.Factory.StartNew(() =>
        {
            if (this.DisplayMini8 is null || this.Hardwares.Mini8Channels is null || this.Hardwares.Mini8s is null || this.Mini8DisplayStatus is null)
                return;
            App.Current.Dispatcher.Invoke(() =>
            {
                this.DisplayMini8.Clear();
            });

            foreach (var channels in this.Hardwares.Mini8Channels)
            {
                if (channels.Value is null)
                    continue;

                if (!this.Hardwares.Mini8s.TryGetValue(channels.Key, out Mini8Info? mini8Info) || mini8Info is null)
                    continue;

                switch (para)
                {
                    case "All":
                        App.Current.Dispatcher.Invoke(() =>
                        {
                            this.DisplayMini8[mini8Info] ??= [];
                            this.DisplayMini8[mini8Info].AddRange(channels.Value.Values);
                        });
                        break;

                    case "Enable":
                        switch (mini8Info.Status)
                        {
                            case Mini8Status.Normal:
                            case Mini8Status.Error:
                            case Mini8Status.Warning:
                            case Mini8Status.LostConnection:
                                App.Current.Dispatcher.Invoke(() =>
                                {
                                    this.DisplayMini8[mini8Info] ??= [];
                                    this.DisplayMini8[mini8Info].AddRange(channels.Value.Values);
                                });
                                break;
                            default:
                                break;
                        }
                        break;

                    case "Alarm":
                        switch (mini8Info.Status)
                        {
                            case Mini8Status.Error:
                            case Mini8Status.Warning:
                            case Mini8Status.LostConnection:
                                App.Current.Dispatcher.Invoke(() =>
                                {
                                    this.DisplayMini8[mini8Info] ??= [];
                                    this.DisplayMini8[mini8Info].AddRange(channels.Value.Values);
                                });
                                break;
                            default:
                                break;
                        }
                        break;
                    default:
                        return;
                }
                //Thread.Sleep(50);
            }
            if (this.Mini8DisplayStatus is null)
                return;
            foreach (var item in this.Mini8DisplayStatus)
                item.Value.IsDisplay = this.DisplayMini8!.ContainsKey(item.Key);
        });
    }

    [RelayCommand]
    private void ChannelDisplay(string para)
    {
        this.Rows = para switch
        {
            "1" => 1,
            "2" => 2,
            "4" => 4,
            _ => 1
        };
    }

    [RelayCommand]
    private void Reconnect(Mini8Info mini8)
    {
        Task.Factory.StartNew(() =>
        {
            this._sender.ReconnectMini8(mini8.Index);
        });
    }
}

public partial class DisplayDetail : ObservableObject
{
    public DisplayDetail(bool isDisplay) => this.IsDisplay = isDisplay;

    [ObservableProperty]
    private bool _IsDisplay;
}