using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using ScadaLink.Commons.Interfaces.Protocol;
using ScadaLink.DataConnectionLayer.Adapters;

namespace ScadaLink.DataConnectionLayer;

/// <summary>
/// WP-34: Default factory that resolves protocol type strings to IDataConnection adapters.
/// Protocol extensibility: register new adapters via the constructor or AddAdapter method.
/// </summary>
public class DataConnectionFactory : IDataConnectionFactory
{
    private readonly Dictionary<string, Func<IDictionary<string, string>, IDataConnection>> _factories = new(StringComparer.OrdinalIgnoreCase);
    private readonly ILoggerFactory _loggerFactory;

    public DataConnectionFactory(ILoggerFactory loggerFactory)
        : this(loggerFactory, Options.Create(new OpcUaGlobalOptions())) { }

    public DataConnectionFactory(ILoggerFactory loggerFactory, IOptions<OpcUaGlobalOptions> opcUaGlobalOptions)
    {
        _loggerFactory = loggerFactory;
        var globalOptions = opcUaGlobalOptions.Value;

        // Register built-in protocols
        RegisterAdapter("OpcUa", details => new OpcUaDataConnection(
            new RealOpcUaClientFactory(globalOptions),
            _loggerFactory.CreateLogger<OpcUaDataConnection>()));
    }

    /// <summary>
    /// Registers a new protocol adapter factory. This is the extension point
    /// for adding new protocols without modifying existing code.
    /// </summary>
    public void RegisterAdapter(string protocolType, Func<IDictionary<string, string>, IDataConnection> factory)
    {
        _factories[protocolType] = factory;
    }

    public IDataConnection Create(string protocolType, IDictionary<string, string> connectionDetails)
    {
        if (!_factories.TryGetValue(protocolType, out var factory))
            throw new ArgumentException($"Unknown protocol type: {protocolType}. Registered protocols: {string.Join(", ", _factories.Keys)}");

        return factory(connectionDetails);
    }
}
