using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;

namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Health;

/// <summary>
///     Pushes the synthetic top-level transport-health entry into the
///     <see cref="HostStatusAggregator"/>. Each driver instance has one entry under its
///     <c>MxAccess.ClientName</c> reflecting the gateway transport state — useful for
///     dashboards that want a single "Galaxy is up" signal independent of any individual
///     platform's ScanState.
/// </summary>
/// <remarks>
///     The eventual production source for this signal is the gateway's <c>StreamSessionHealth</c>
///     RPC. Until that ships, the driver-side reconnect supervisor
///     (PR 4.5) calls <see cref="SetTransport"/> on transport state transitions:
///     <see cref="HostState.Running"/> when the gw session re-Registers, <see cref="HostState.Stopped"/>
///     when the supervisor moves to <c>TransportLost</c>. The forwarder is intentionally
///     stateless beyond the cached client name + last-pushed value so the supervisor can
///     drive it without any back-pressure plumbing.
/// </remarks>
public sealed class HostConnectivityForwarder : IDisposable
{
    private readonly string _clientName;
    private readonly HostStatusAggregator _aggregator;
    private readonly ILogger _logger;
    private bool _disposed;

    /// <summary>Initializes a new instance of HostConnectivityForwarder with the given client name, aggregator, and optional logger.</summary>
    /// <param name="clientName">The client name for the MxAccess connection.</param>
    /// <param name="aggregator">The host status aggregator to push connectivity state to.</param>
    /// <param name="logger">The optional logger for diagnostic messages.</param>
    public HostConnectivityForwarder(string clientName, HostStatusAggregator aggregator, ILogger? logger = null)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(clientName);
        _clientName = clientName;
        _aggregator = aggregator ?? throw new ArgumentNullException(nameof(aggregator));
        _logger = logger ?? NullLogger.Instance;
    }

    /// <summary>
    ///     Push a transport state into the aggregator. Idempotent at the aggregator layer —
    ///     repeated calls with the same state don't fan out duplicate transitions.
    /// </summary>
    /// <param name="state">The host connectivity state to push.</param>
    public void SetTransport(HostState state)
    {
        ObjectDisposedException.ThrowIf(_disposed, this);
        var status = new HostConnectivityStatus(_clientName, state, DateTime.UtcNow);
        _aggregator.Update(status);
        _logger.LogDebug(
            "GalaxyDriver transport state for {ClientName}: {State}",
            _clientName, state);
    }

    /// <summary>Disposes the forwarder and marks it as disposed.</summary>
    public void Dispose()
    {
        // No-op today; reserved for the eventual StreamSessionHealth consumer that
        // will own a long-running task this method tears down.
        _disposed = true;
    }
}
