using AlarmInfoServerSim.Services;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HardwareData;
using RealtimeData;
using RTCommunicatorBase;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.Text;

namespace AlarmInfoServerSim.ViewModels;

public partial class WorkAreaViewModel : ObservableObject
{
    private readonly ILogService _logService;
    private readonly IInfoSendingService _infoSendingService;

    private readonly Hardwares _hardwares;

    [ObservableProperty]
    private ConcurrentDictionary<byte, Mini8Data> _mini8;

    [ObservableProperty]
    private int _selectedMini8Index = -1;

    [ObservableProperty]
    private ConcurrentDictionary<byte, ChannelData> _mini8Channel;

    [ObservableProperty]
    private int _selectedChannelIndex = -1;

    [ObservableProperty]
    private AlarmType[] _alarmTypes;

    [ObservableProperty]
    private int _selectedAlarmTypeIndex = -1;

    [ObservableProperty]
    private float _pV;

    [ObservableProperty]
    private float _caps;

    [ObservableProperty]
    private float _floor;

    [ObservableProperty]
    private ObservableCollection<string> _receivedTlvData;

    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(SendInfoCommand))]
    private bool _hasConnection;



    public WorkAreaViewModel(ILogService logService, ISharedConfig sharedConfig ,IInfoSendingService infoSendingService)
    {
        if(sharedConfig.Hardwares is null)
        {
            throw new ArgumentNullException(nameof(sharedConfig.Hardwares));
        }
        
        _hardwares = sharedConfig.Hardwares;

        _mini8 = _hardwares.Mini8s;
        _mini8Channel = [];
        _alarmTypes = Enum.GetValues<AlarmType>();
        _receivedTlvData = [];

        _logService= logService;
        _infoSendingService = infoSendingService;
        _infoSendingService.ConnectionChanged += OnConnectionChanged;
        _infoSendingService.DataReceived += OnDataReceived;
    }

    partial void OnSelectedMini8IndexChanged(int value)
    {
        SelectedChannelIndex = -1;
        SelectedAlarmTypeIndex = -1;
        Mini8Channel = _hardwares.Mini8Channels[Mini8.ElementAt(value).Key];
    }

    partial void OnSelectedChannelIndexChanged(int value)
    {
        SelectedAlarmTypeIndex = -1;
    }

    [RelayCommand(CanExecute = nameof(HasConnection))]
    private void SendInfo()
    {
        if (SelectedMini8Index == -1 || SelectedChannelIndex == -1 || SelectedAlarmTypeIndex == -1)
        {
            _logService.Log("Failed to send information, please select every ComboBox");
            return;
        }

        // ChannelAlarmNotify = 1
        _infoSendingService.Send(1, new ST_ALARM()
        {
            Mini8Index = Mini8.ElementAt(SelectedMini8Index).Key,
            ChannelIndex = Mini8Channel.ElementAt(SelectedChannelIndex).Key,
            PV = PV,
            Caps = Caps,
            Floor = Floor,
            AlarmType = (AlarmType)SelectedAlarmTypeIndex
        });
    }

    private void OnConnectionChanged(object? sender, (bool, UniversalNetFrame451.IO.TcpConnection) e)
    {
        App.Current.Dispatcher.Invoke(() =>
        {
            HasConnection = e.Item1;
        });
    }

    private void OnDataReceived(object? sender, (ushort, TLVProtocal.TlvData) e)
    {
        App.Current.Dispatcher.Invoke(() =>
        {
            if (ReceivedTlvData.Count >= 50)
            {
                ReceivedTlvData.RemoveAt(ReceivedTlvData.Count - 1);
            }

            string fileName = Encoding.UTF8.GetString(e.Item2.RawData);
            ReceivedTlvData.Insert(0, e.Item2.DateTime.ToString() + $" {fileName}");
        });
    }
}
