using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ZB.MOM.WW.ScadaBridge.HealthMonitoring;

namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Streaming;

/// <summary>
/// WP2.6d (arch-review misc — site stream alarm-vs-attribute shared buffer): site-side
/// hosted service that periodically reads <see cref="SiteStreamManager.AlarmPublishDroppedCount"/>
/// and pushes it into <see cref="ISiteHealthCollector.SetSiteStreamAlarmDropCount"/> so
/// the next <see cref="ISiteHealthCollector.CollectReport"/> carries a fresh snapshot on
/// the site health report. Mirrors <c>ScriptSchedulerStatsReporter</c>: immediate first
/// probe, fixed cadence, exceptions logged and swallowed so the loop survives every probe
/// failure.
/// </summary>
public sealed class SiteStreamAlarmDropReporter : BackgroundService
{
    /// <summary>Default poll cadence (10 s) — coarse enough to amortise across health reports.</summary>
    internal static readonly TimeSpan DefaultPollInterval = TimeSpan.FromSeconds(10);

    private readonly ISiteHealthCollector _collector;
    private readonly SiteStreamManager _streamManager;
    private readonly ILogger<SiteStreamAlarmDropReporter> _logger;
    private readonly TimeSpan _pollInterval;

    /// <summary>Initializes a new instance of <see cref="SiteStreamAlarmDropReporter"/>.</summary>
    /// <param name="collector">The site health collector that receives the drop count.</param>
    /// <param name="streamManager">The site stream manager whose alarm-queue drop count is sampled.</param>
    /// <param name="logger">Logger instance.</param>
    /// <param name="pollInterval">Poll interval override; defaults to <see cref="DefaultPollInterval"/> (10 s).</param>
    public SiteStreamAlarmDropReporter(
        ISiteHealthCollector collector,
        SiteStreamManager streamManager,
        ILogger<SiteStreamAlarmDropReporter> logger,
        TimeSpan? pollInterval = null)
    {
        _collector = collector ?? throw new ArgumentNullException(nameof(collector));
        _streamManager = streamManager ?? throw new ArgumentNullException(nameof(streamManager));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _pollInterval = pollInterval ?? DefaultPollInterval;
    }

    /// <inheritdoc />
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Immediate first probe so the first health report after start carries a
        // real snapshot instead of a zero.
        Probe();

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                await Task.Delay(_pollInterval, stoppingToken).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
                break;
            }

            Probe();
        }
    }

    private void Probe()
    {
        try
        {
            _collector.SetSiteStreamAlarmDropCount(_streamManager.AlarmPublishDroppedCount);
        }
        catch (Exception ex)
        {
            // Catch-all is deliberate: the hosted service must survive every class
            // of probe failure so the next tick gets a chance.
            _logger.LogWarning(ex, "SiteStreamAlarmDropReporter probe failed; next tick will retry.");
        }
    }
}
