using System.Reflection;
using System.Security.Claims;
using Bunit;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using NSubstitute;
using ZB.MOM.WW.ScadaBridge.CentralUI.Auth;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.DebugView;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Streaming;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Alarms;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
using ZB.MOM.WW.ScadaBridge.Communication;
using ZB.MOM.WW.ScadaBridge.Communication.Grpc;
using DebugViewPage = ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.Deployment.DebugView;

namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Deployment;

/// <summary>
/// Task 23: the DebugView alarm table surfaces enriched native alarm state —
/// kind, severity, source reference, and a composite condition badge set
/// (Unacked / Shelved / Suppressed).
/// </summary>
public class DebugViewAlarmTableTests : BunitContext
{
    private IRenderedComponent<DebugViewPage> RenderPage()
    {
        JSInterop.Mode = JSRuntimeMode.Loose;

        var repo = Substitute.For<ITemplateEngineRepository>();
        var siteRepo = Substitute.For<ISiteRepository>();
        siteRepo.GetAllSitesAsync().Returns(new List<Site>());
        Services.AddSingleton(repo);
        Services.AddSingleton(siteRepo);

        var comms = new CommunicationService(
            Options.Create(new CommunicationOptions()),
            NullLogger<CommunicationService>.Instance);
        Services.AddSingleton(comms);

        var grpcFactory = new SiteStreamGrpcClientFactory(NullLoggerFactory.Instance);
        var debugStream = new DebugStreamService(
            comms, new ServiceCollection().BuildServiceProvider(), grpcFactory,
            NullLogger<DebugStreamService>.Instance);
        Services.AddSingleton(debugStream);

        var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "deployer") }, "TestCookie");
        var stubAuth = new StubAuthStateProvider(new AuthenticationState(new ClaimsPrincipal(identity)));
        Services.AddSingleton<AuthenticationStateProvider>(stubAuth);
        Services.AddScoped(_ => new SiteScopeService(stubAuth));

        return Render<DebugViewPage>();
    }

    private sealed class StubAuthStateProvider : AuthenticationStateProvider
    {
        private readonly AuthenticationState _state;
        public StubAuthStateProvider(AuthenticationState state) => _state = state;
        public override Task<AuthenticationState> GetAuthenticationStateAsync() => Task.FromResult(_state);
    }

    private static void SetField(DebugViewPage c, string name, object? value) =>
        typeof(DebugViewPage).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic)!.SetValue(c, value);

    private static Dictionary<string, AlarmStateChanged> AlarmStates(DebugViewPage c) =>
        (Dictionary<string, AlarmStateChanged>)typeof(DebugViewPage)
            .GetField("_alarmStates", BindingFlags.Instance | BindingFlags.NonPublic)!.GetValue(c)!;

    [Fact]
    public void AlarmTable_RendersNativeAlarm_WithSeverityKindAndShelvedBadge()
    {
        var cut = RenderPage();

        var native = new AlarmStateChanged("inst", "T01.Hi", AlarmState.Active, 800, DateTimeOffset.UtcNow)
        {
            Kind = AlarmKind.NativeOpcUa,
            SourceReference = "ns=2;s=Tank01.Level.HiHi",
            Condition = new AlarmConditionState(
                Active: true, Acknowledged: false, Confirmed: null,
                Shelve: AlarmShelveState.OneShotShelved, Suppressed: false, Severity: 800)
        };

        cut.InvokeAsync(() =>
        {
            SetField(cut.Instance, "_connected", true);
            SetField(cut.Instance, "_snapshot",
                new DebugViewSnapshot("inst", new List<AttributeValueChanged>(),
                    new List<AlarmStateChanged> { native }, DateTimeOffset.UtcNow));
            AlarmStates(cut.Instance)["T01.Hi"] = native;
        });
        cut.Render();

        var markup = cut.Markup;
        Assert.Contains("800", markup);                 // severity surfaced
        Assert.Contains("Shelved", markup);             // composite condition badge
        Assert.Contains("OPC UA", markup);              // native kind badge
        Assert.Contains("ns=2;s=Tank01.Level.HiHi", markup); // source reference
        Assert.Contains("Unacked", markup);             // active + unacknowledged
    }
}
