using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
namespace ZB.MOM.WW.ScadaBridge.InboundAPI;
public static class ServiceCollectionExtensions
{
///
/// Registers all inbound API services (script executor, route helper, and endpoint filter).
///
/// The service collection to register into.
/// The same to allow chaining.
public static IServiceCollection AddInboundAPI(this IServiceCollection services)
{
// Inbound authentication is handled by the shared
// ZB.MOM.WW.Auth.ApiKeys verifier (Bearer sbk__), registered by
// AddZbApiKeyAuth in the Host composition root. The legacy ApiKeyValidator +
// peppered IApiKeyHasher and the SQL Server ApiKey store were retired, so this
// extension no longer registers them.
services.AddSingleton();
services.AddScoped();
// Short-TTL cache of resolved ApiMethod rows, sitting in front of the
// per-request repository fetch in EndpointExtensions. Invalidated by name via
// ScriptArtifactChangeSubscriber (below) and self-heals via TTL expiry for
// changes the bus does not cover.
services.AddSingleton(sp => new ApiMethodCache(
sp.GetRequiredService>().Value.ApiMethodCacheTtl));
// Routed calls go through the IInstanceRouter seam; the
// production implementation delegates to CommunicationService.
services.AddScoped();
// Endpoint filter enforcing the request
// body size cap and active-node gating for POST /api/{methodName}.
services.AddSingleton();
// Standby-node forwarding (2026-08-28): a standby relays POST /api/{methodName}
// to the active peer over HTTP instead of answering 503 STANDBY_NODE. The
// named client has no HttpClient.Timeout of its own — the forwarder's per-attempt
// CTS (InboundApiOptions.StandbyForwardTimeout) is the single deadline, so a
// long-running method on the active node is not cut off by a second, hidden cap.
services.AddHttpClient(HttpStandbyRequestForwarder.HttpClientName)
.ConfigureHttpClient(c => c.Timeout = Timeout.InfiniteTimeSpan);
services.AddSingleton();
// N1: the ApiMethod consumer of the script-artifact invalidation bus.
// The bus parameter is optional — hosts without a registered
// IScriptArtifactChangeBus (site roles, plain test hosts) start it as a no-op
// and the executor's per-request revision check alone keeps handlers fresh.
services.AddHostedService();
// ScadaBridge#103: a create / update / delete / recompile made through the other central
// node drops this node's handler, known-bad record and cached row for the method.
services.TryAddEnumerable(ServiceDescriptor.Singleton());
return services;
}
}