using Microsoft.Extensions.Logging.Abstractions;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Configuration.LocalCache;
using ZB.MOM.WW.OtOpcUa.Server;

namespace ZB.MOM.WW.OtOpcUa.Server.Tests;

[Trait("Category", "Unit")]
public sealed class NodeBootstrapTests
{
    private sealed class StubCache : ILocalConfigCache
    {
        public GenerationSnapshot? Stored { get; set; }
        public Task<GenerationSnapshot?> GetMostRecentAsync(string _, CancellationToken __) => Task.FromResult(Stored);
        public Task PutAsync(GenerationSnapshot _, CancellationToken __) => Task.CompletedTask;
        public Task PruneOldGenerationsAsync(string _, int __, CancellationToken ___) => Task.CompletedTask;
    }

    [Fact]
    public async Task Falls_back_to_cache_when_DB_unreachable()
    {
        var cache = new StubCache
        {
            Stored = new GenerationSnapshot
            {
                ClusterId = "c", GenerationId = 42, CachedAt = DateTime.UtcNow, PayloadJson = "{}",
            },
        };

        var bootstrap = new NodeBootstrap(
            new NodeOptions
            {
                NodeId = "n",
                ClusterId = "c",
                ConfigDbConnectionString = "Server=127.0.0.1,59999;Database=nope;User Id=x;Password=x;TrustServerCertificate=True;Connect Timeout=1;",
            },
            cache,
            NullLogger<NodeBootstrap>.Instance);

        var result = await bootstrap.LoadCurrentGenerationAsync(CancellationToken.None);

        result.Source.ShouldBe(BootstrapSource.LocalCache);
        result.GenerationId.ShouldBe(42);
    }

    [Fact]
    public async Task Throws_BootstrapException_when_DB_unreachable_and_cache_empty()
    {
        var bootstrap = new NodeBootstrap(
            new NodeOptions
            {
                NodeId = "n",
                ClusterId = "c",
                ConfigDbConnectionString = "Server=127.0.0.1,59999;Database=nope;User Id=x;Password=x;TrustServerCertificate=True;Connect Timeout=1;",
            },
            new StubCache(),
            NullLogger<NodeBootstrap>.Instance);

        await Should.ThrowAsync<BootstrapException>(() =>
            bootstrap.LoadCurrentGenerationAsync(CancellationToken.None));
    }
}
