using RobotNet.Script;
using RobotNet.ScriptManager.Connections;

namespace RobotNet.ScriptManager.Services;

public class ScriptConnectionManager : IConnectionManager
{
    private readonly SemaphoreSlim _connectLock = new(1, 1);
    private readonly Dictionary<string, IModbusTcpClient> ModbusTcpConnections = [];
    private readonly Dictionary<string, ICcLinkIeBasicClient> CcLinkConnections = [];

    public void Reset()
    {
        foreach (var client in ModbusTcpConnections.Values)
        {
            client.Dispose();
        }
        ModbusTcpConnections.Clear();

        foreach (var client in CcLinkConnections.Values)
        {
            client.Dispose();
        }
        CcLinkConnections.Clear();
    }

    public async Task<IModbusTcpClient> ConnectModbusTcp(string ipAddress, int port, byte unitId)
    {
        string key = $"{ipAddress}:{port}:{unitId}";
        await _connectLock.WaitAsync().ConfigureAwait(false);

        try
        {
            if (ModbusTcpConnections.TryGetValue(key, out var existingClient))
            {
                return existingClient;
            }
            else
            {
                var client = new ModbusTcpClient(ipAddress, port, unitId);

                await client.ConnectAsync();

                ModbusTcpConnections.Add(key, client);

                return client;
            }
        }
        finally
        {
            _connectLock.Release();
        }
    }

    public async Task<ICcLinkIeBasicClient> ConnectCcLink(IeBasicClientOptions option)
    {
        string key = $"{option.Host}:{option.Port}:{option.NetworkNo}:{option.ModuleIoNo}:{option.MultidropNo}";
        await _connectLock.WaitAsync().ConfigureAwait(false);

        try
        {
            if (CcLinkConnections.TryGetValue(key, out var existingClient))
            {
                return existingClient;
            }
            else
            {
                var client = new CcLinkIeBasicClient(option);
                await client.ConnectAsync();

                CcLinkConnections.Add(key, client);
                return client;
            }
        }
        finally
        {
            _connectLock.Release();
        }
    }
}
