namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;

/// <summary>
///     Abstraction over the process-wide driver registry. Runtime consumes this instead of
///     <c>DriverFactoryRegistry</c> directly so the Runtime project doesn't pull in
///     <c>ZB.MOM.WW.OtOpcUa.Core</c> (which would drag in Polly + driver hosting). The fused
///     Host binds a <c>DriverFactoryRegistryAdapter</c> after every <c>Driver.*.Register()</c>
///     extension has run.
/// </summary>
public interface IDriverFactory
{
    /// <summary>
    ///     Return a new <see cref="IDriver"/> for the given <paramref name="driverType"/>, or
    ///     <c>null</c> when no factory is registered for that type (missing assembly, typo, etc.).
    ///     The DriverHostActor logs + skips the row rather than failing the whole apply.
    /// </summary>
    /// <param name="driverType">The driver type name (e.g., "Modbus", "FOCAS").</param>
    /// <param name="driverInstanceId">The driver instance identifier.</param>
    /// <param name="driverConfigJson">The driver configuration as a JSON string.</param>
    /// <returns>A new IDriver instance, or null if the driver type is not supported.</returns>
    IDriver? TryCreate(string driverType, string driverInstanceId, string driverConfigJson);

    /// <summary>Driver-type names this factory can materialise. Mostly for diagnostics + logs.</summary>
    IReadOnlyCollection<string> SupportedTypes { get; }
}

/// <summary>
///     Returns <c>null</c> from every <see cref="IDriverFactory.TryCreate"/> call. Bound when the
///     fused Host hasn't registered any concrete driver assemblies yet (Mac dev path, smoke
///     tests). DriverHostActor sees zero supported types and treats the deployment as a no-op.
/// </summary>
public sealed class NullDriverFactory : IDriverFactory
{
    public static readonly NullDriverFactory Instance = new();
    private NullDriverFactory() { }

    /// <inheritdoc />
    public IDriver? TryCreate(string driverType, string driverInstanceId, string driverConfigJson) => null;
    /// <inheritdoc />
    public IReadOnlyCollection<string> SupportedTypes { get; } = Array.Empty<string>();
}
