using ZB.MOM.WW.MxGateway.Client;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Runtime;

namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests.Runtime;

/// <summary>
///     D.1 smoke (alarm-source leg): drives the REAL gateway <c>StreamAlarms</c> feed through the
///     production lmxopcua consumer (<see cref="GatewayGalaxyAlarmFeed"/>) and asserts native alarm
///     transitions — with operator comment, category, original raise time, and the mapped OPC UA
///     severity bucket preserved — reach the driver-side boundary that feeds
///     <c>IAlarmSource.OnAlarmEvent</c>.
///     <para>
///     Skip-gated: runs only when <c>MXGW_ENDPOINT</c> + <c>GALAXY_MXGW_API_KEY</c> are set to a
///     reachable gateway. Captured 2026-05-29 against <c>10.100.0.48:5120</c> — see
///     <c>docs/plans/alarms-d1-smoke-artifact.md</c>. Set <c>D1_SMOKE_OUT</c> to dump the observed
///     transitions to a file for artifact capture.
///     </para>
/// </summary>
[Trait("Category", "Integration")]
public sealed class GatewayGalaxyAlarmFeedLiveTests
{
    [Fact]
    public async Task Live_gateway_delivers_native_alarm_transitions_through_the_consumer()
    {
        var endpoint = Environment.GetEnvironmentVariable("MXGW_ENDPOINT");
        var apiKey = Environment.GetEnvironmentVariable("GALAXY_MXGW_API_KEY");
        if (string.IsNullOrWhiteSpace(endpoint) || string.IsNullOrWhiteSpace(apiKey))
            Assert.Skip("Set MXGW_ENDPOINT + GALAXY_MXGW_API_KEY to run the live gateway alarm-feed smoke.");

        var client = MxGatewayClient.Create(new MxGatewayClientOptions
        {
            Endpoint = new Uri(endpoint!, UriKind.Absolute),
            ApiKey = apiKey!,
            UseTls = false,
            ConnectTimeout = TimeSpan.FromSeconds(10),
            DefaultCallTimeout = TimeSpan.FromSeconds(30),
            StreamTimeout = TimeSpan.FromSeconds(30),
        });

        var observed = new List<GalaxyAlarmTransition>();
        var gotOne = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);

        // Wire the live client's StreamAlarms method group into the production consumer seam.
        await using var feed = new GatewayGalaxyAlarmFeed(client.StreamAlarmsAsync, clientName: "D1Smoke");
        feed.OnAlarmTransition += (_, t) =>
        {
            lock (observed) { observed.Add(t); }
            gotOne.TrySetResult(true);
        };
        feed.Start();

        // The stream opens with the active-alarm snapshot, so we expect ≥1 transition promptly.
        await Task.WhenAny(gotOne.Task, Task.Delay(TimeSpan.FromSeconds(20), TestContext.Current.CancellationToken));

        List<GalaxyAlarmTransition> snapshot;
        lock (observed) snapshot = observed.ToList();

        snapshot.ShouldNotBeEmpty(
            "Live gateway should deliver at least the active-alarm snapshot through the lmxopcua consumer.");
        var first = snapshot[0];
        first.AlarmFullReference.ShouldNotBeNullOrWhiteSpace();
        first.OpcUaSeverity.ShouldBeGreaterThan(0); // severity bucket mapping applied by the consumer

        foreach (var t in snapshot.Take(8))
            TestContext.Current.SendDiagnosticMessage(
                $"{t.TransitionKind,-11} {t.AlarmFullReference}  sev={t.OpcUaSeverity}({t.SeverityBucket})  cat={t.Category}  comment='{t.OperatorComment}'");
        TestContext.Current.SendDiagnosticMessage($"TOTAL consumer transitions observed: {snapshot.Count}");

        // Deterministic artifact capture (only when D1_SMOKE_OUT is set).
        var outPath = Environment.GetEnvironmentVariable("D1_SMOKE_OUT");
        if (!string.IsNullOrWhiteSpace(outPath))
        {
            var lines = snapshot.Take(50).Select(t =>
                $"{t.TransitionKind,-11} {t.AlarmFullReference} | sev={t.OpcUaSeverity}({t.SeverityBucket}) raw={t.RawMxAccessSeverity} | cat={t.Category} | comment='{t.OperatorComment}' | xitionUtc={t.TransitionTimestampUtc:o}");
            await File.WriteAllLinesAsync(outPath!,
                new[] { $"# consumer transitions observed: {snapshot.Count}" }.Concat(lines),
                TestContext.Current.CancellationToken);
        }
    }
}
