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

/// <summary>
///     Builds a per-driver-instance <see cref="IDriverCapabilityInvoker"/>. The Runtime
///     <c>DriverHostActor</c> consumes this factory (resolved from DI, like <see cref="IDriverFactory"/>)
///     to attach a resilience invoker to each spawned <c>DriverInstanceActor</c> WITHOUT the actor
///     assembly referencing <c>ZB.MOM.WW.OtOpcUa.Core</c> (which drags in Polly). The fused Host
///     binds a concrete factory closing over the process-singleton pipeline builder + status tracker +
///     driver-tier resolver; when unbound, <see cref="NullDriverCapabilityInvokerFactory"/> yields the
///     pass-through invoker so dispatch behaves exactly as before.
/// </summary>
public interface IDriverCapabilityInvokerFactory
{
    /// <summary>
    ///     Create the resilience invoker for one driver instance. The returned invoker is keyed on
    ///     <paramref name="driverInstanceId"/> and applies the tier policy resolved from
    ///     <paramref name="driverType"/>, layering any per-instance
    ///     <paramref name="resilienceConfigJson"/> overrides on top.
    /// </summary>
    /// <param name="driverInstanceId">The driver instance identifier (pipeline + tracker key).</param>
    /// <param name="driverType">The driver type name, used to resolve the resilience tier defaults.</param>
    /// <param name="resilienceConfigJson">
    ///     Optional per-instance <c>DriverInstance.ResilienceConfig</c> JSON (from the deployment artifact)
    ///     layered on top of the tier defaults. <c>null</c>/empty ⇒ pure tier defaults. A concrete factory
    ///     invalidates any cached pipelines for <paramref name="driverInstanceId"/> so a changed config
    ///     applied across a driver respawn takes effect (the pipeline cache is keyed on instance/host/
    ///     capability, not options).
    /// </param>
    /// <returns>A per-instance <see cref="IDriverCapabilityInvoker"/>.</returns>
    IDriverCapabilityInvoker Create(string driverInstanceId, string driverType, string? resilienceConfigJson = null);
}

/// <summary>
///     Returns <see cref="NullDriverCapabilityInvoker.Instance"/> for every driver instance. Bound
///     when the fused Host hasn't registered a real resilience factory (Mac dev path, smoke tests,
///     admin-only nodes). Dispatch then routes calls straight through with no pipeline.
/// </summary>
public sealed class NullDriverCapabilityInvokerFactory : IDriverCapabilityInvokerFactory
{
    /// <summary>The shared singleton instance.</summary>
    public static readonly NullDriverCapabilityInvokerFactory Instance = new();
    private NullDriverCapabilityInvokerFactory() { }

    /// <inheritdoc />
    public IDriverCapabilityInvoker Create(string driverInstanceId, string driverType, string? resilienceConfigJson = null) =>
        NullDriverCapabilityInvoker.Instance;
}
