namespace MinicsConsole.Helper;

public class Mini8DataDispatcher
{
    public Mini8DataDispatcher(ILog log,
        UISender uiNotifier,
        RTNotifier rtNotifer,
        PLCNotifier plcNotifier)
        //KanbanNotifier kanbanNotifier)
    {
        this._log = log;
        this._Connectors.TryAdd("PLC", plcNotifier);
        this._Connectors.TryAdd("UI", uiNotifier);
        this._Connectors.TryAdd("RT", rtNotifer);
        //this._Connectors.TryAdd("Kanban", kanbanNotifier);

        this._UINotifier = uiNotifier;
        this._PlcNotifier = plcNotifier;
        this._RTNotifier = rtNotifer;

        this._UIQueue = new(UIQueueHandler);
        this._RTQueue = new(RTQueueHandler);
        this._PLCQueue = new(PLCQueueHandler);
    }

    private readonly ILog _log;

    private readonly ConcurrentDictionary<string, IMini8DataNotifier> _Connectors = [];

    private readonly IMini8DataNotifier _UINotifier;
    private readonly IMini8DataNotifier _PlcNotifier;
    private readonly IMini8DataNotifier _RTNotifier;

    private readonly EventQueue<(byte mini8, byte channel, ChannelData channelData)> _UIQueue;
    private readonly EventQueue<(byte mini8, byte channel, ChannelData channelData)> _PLCQueue;
    private readonly EventQueue<(byte mini8, byte channel, ChannelData channelData)> _RTQueue;

    private void RTQueueHandler((byte mini8, byte channel, ChannelData channelData) t)
    {
        if (this._RTQueue.Count >= 2)
            return;

        try
        {
            this._RTNotifier?.ChannelInfoNotify(t.mini8, t.channel, t.channelData);
        }
        catch
        {
            _log?.Warning($"DataDispatcher try send ChannelInfoNotify failed RT mini8 {t.mini8} channel {t.channel}");
        }
    }

    private void UIQueueHandler((byte mini8, byte channel, ChannelData channelData) t)
    {
        if (this._UIQueue.Count >= 2)
            return;

        try
        {
            this._UINotifier?.ChannelInfoNotify(t.mini8, t.channel, t.channelData);
        }
        catch
        {
            _log?.Warning($"DataDispatcher try send ChannelInfoNotify failed UI mini8 {t.mini8} channel {t.channel}");
        }
    }

    private void PLCQueueHandler((byte mini8, byte channel, ChannelData channelData) t)
    {
        if (this._PLCQueue.Count >= 2)
            return;

        try
        {
            this._PlcNotifier?.ChannelInfoNotify(t.mini8, t.channel, t.channelData);
        }
        catch
        {
            _log?.Warning($"DataDispatcher try send ChannelInfoNotify failed PLC mini8 {t.mini8} channel {t.channel}");
        }
    }

    public void ChannelInfoNotify(byte mini8, byte channel, ChannelData channelData)
    {
        if (channelData is null)
            return;
        _RTQueue.Enqueue((mini8, channel, channelData));
        _PLCQueue.Enqueue((mini8, channel, channelData));
        _UIQueue.Enqueue((mini8, channel, channelData));
    }

    public void AlarmNotify(byte mini8, byte channel, float temperature)
    {
        Parallel.ForEach(_Connectors.Values, item =>
        {
            try
            {
                item.AlarmNotify(mini8, channel, temperature);
            }
            catch
            {
                _log.Warning($"DataDispatcher try send AlarmNotify failed {item.Name} mini8 {mini8} channel {channel}");
            }
        });
    }

    public void AlarmTcBrockenNotify(byte mini8, byte channel)
    {
        Parallel.ForEach(_Connectors.Values, item =>
        {
            try
            {
                item.AlarmTcBrockenNotify(mini8, channel);
            }
            catch
            {
                _log.Warning($"DataDispatcher try send AlarmTcBrockenNotify failed {item.Name} mini8 {mini8} channel {channel}");
            }
        });
    }

    public void Mini8Connect(byte mini8Index)
    {
        Parallel.ForEach(_Connectors.Values, item =>
        {
            try
            {
                item.Mini8ConnectNotify(mini8Index, true);
            }
            catch
            {
                _log.Warning($"DataDispatcher try send Mini8Connect to failed {item.Name} mini8 {mini8Index}");
            }
        });
    }

    public void Mini8Disconnect(byte mini8Index)
    {
        Parallel.ForEach(_Connectors.Values, item =>
        {
            try
            {
                item.Mini8ConnectNotify(mini8Index, false);
            }
            catch
            {
                _log.Warning($"DataDispatcher try send Mini8Disconnect failed {item.Name} mini8 {mini8Index}");
            }
        });
    }
}
