using RTCommunicatorBase;
using System.Collections.Concurrent;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using TLVProtocal;  
using UniversalNetFrame451;
using UniversalNetFrame451.IO;

namespace RTCommunicatorTLV;

public class RTCommunicator_TLV : IRTMini8Sender, ITlvProvider
{
    private IRTMini8Provider _provider;
    private ITlvCommunicatorClient _client;
    private readonly ConcurrentDictionary<byte, Timer> _DisconnectNotifyTimer = [];

    public bool Initialize(IRTMini8Provider provider)
    {
        if (provider is null)
            return false;

        if (this._provider is not null)
            return false;

        this._provider = provider;
        return true;
    }
    public bool StartService(string ip, int port)
    {
        if (_provider is null)
            return false;

        if (this._client is not null)
            return false;

        if (string.IsNullOrEmpty(ip) || port < 5000 || port > ushort.MaxValue)
            return false;

        ITlvCommunicatorClient client = TlvFactory.GetTlvClient();
        if (!client.Initialize(this, false, 500))
            return false;



        Task.Factory.StartNew(() =>
        {
            while (!client.Open(ip, (ushort)port))
            {
                Thread.Sleep(1000);
            }
            this._client = client;

            this._provider?.Connected(ip, port);

        });

        return true;
    }
    public bool CloseService()
    {
        this._client?.Dispose();
        this._client = null;
        this._provider = null;
        return true;
    }

    public bool SelectConfigFile(string name)
    {
        if (this._client is null)
            return false;
        if (string.IsNullOrEmpty(name))
            return false;

        byte[] bytes = Encoding.UTF8.GetBytes(name);
        TlvData data = new(1, bytes);
        return this._client?.SendNotify(data) == true;
    }

    void ITlvProvider.Received(TlvData data)
    {
        if (data.RawData is null || data.RawData.Length == 0)
            return;
        Task.Factory.StartNew(() =>
        {
            switch (data.Tag)
            {
                case Tags.CurrentTempConfigFile:
                    string fileName = Encoding.UTF8.GetString(data.RawData);
                    if (string.IsNullOrEmpty(fileName))
                        return;
                    this._provider?.CurrentTempConfigFile(fileName);
                    break;
                case Tags.ChannelAlarmNotify:
                    if (!StructConverter.TryGetStruct(data.RawData, out ST_ALARM? alarm) || alarm is null)
                        return;
                    this._provider?.ChannelAlarmNotify(alarm.Value);
                    break;
                case Tags.Mini8ConnectNotify:
                    {
                        byte index = data.RawData[0];
                        this._DisconnectNotifyTimer.TryRemove(index, out Timer timer);
                        timer?.Dispose();
                        this._provider?.Mini8ConnectNotify(index);
                        break;
                    }
                case Tags.Mini8DisconnectNotify:
                    {
                        byte index = data.RawData[0];
                        if (!this._DisconnectNotifyTimer.ContainsKey(index))
                            this._DisconnectNotifyTimer[index] = new(DisconnectNotifyTimerCallBack, index, 0, 1000);
                        break;
                    }
                default:
                    break;
            }
        });
    }

    TlvData ITlvProvider.RequestReply(TlvData tlvData)
    {
        return tlvData;
    }

    void ITlvProvider.Connected(TcpConnection connection)
    {
        this._provider.Connected(connection.RemoteEndPoint.Address.ToString(), connection.RemoteEndPoint.Port);
    }

    void ITlvProvider.Disconnected(TcpConnection connection)
    {
        this._provider.DisConnected(connection.RemoteEndPoint.Address.ToString(), connection.RemoteEndPoint.Port);
    }

    private void DisconnectNotifyTimerCallBack(object state)
    {
        if (state is not byte index)
            return;

        this._provider?.Mini8DisconnectNotify(index);
    }
}
