using Microsoft.AspNetCore.DataProtection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.ExternalSystems;
using ZB.MOM.WW.ScadaBridge.ConfigurationDatabase;

namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests;

/// <summary>
/// Regression guard for ConfigurationDatabase-013: a <see cref="ScadaBridgeDbContext"/>
/// constructed without an explicit Data Protection provider (the single-argument
/// constructor) must NOT silently encrypt secret columns with a throwaway ephemeral
/// key — that would persist ciphertext that becomes permanently undecryptable on the
/// next process restart, with no error. Writing a secret column on such a context
/// must fail fast with a clear <see cref="InvalidOperationException"/> instead.
/// </summary>
public class EphemeralEncryptionFallbackTests
{
    private static DbContextOptions<ScadaBridgeDbContext> SqliteOptions() =>
        new DbContextOptionsBuilder<ScadaBridgeDbContext>()
            .UseSqlite("DataSource=:memory:")
            .ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning))
            .Options;

    [Fact]
    public async Task SingleArgConstructor_WritingSecretColumn_FailsFast_DoesNotPersistThrowawayCiphertext()
    {
        // Single-argument constructor: no Data Protection provider supplied (the
        // design-time / schema-only path). Schema creation must still succeed.
        using var context = new ScadaBridgeDbContext(SqliteOptions());
        context.Database.OpenConnection();
        context.Database.EnsureCreated();

        // AuthConfiguration is an encrypted secret column. Persisting it without a real
        // key ring would produce undecryptable ciphertext; it must throw instead.
        var ext = new ExternalSystemDefinition("Erp", "https://erp.example.com", "ApiKey")
        {
            AuthConfiguration = "{\"apiKey\":\"live-secret\"}"
        };
        context.ExternalSystemDefinitions.Add(ext);

        var ex = await Assert.ThrowsAsync<InvalidOperationException>(
            () => context.SaveChangesAsync());
        Assert.Contains("Data Protection", ex.Message);
    }

    [Fact]
    public async Task SingleArgConstructor_WritingNonSecretColumn_Succeeds()
    {
        // The schema-only / no-provider context must remain fully usable for entities
        // that have no encrypted secret columns — only secret writes are gated.
        using var context = new ScadaBridgeDbContext(SqliteOptions());
        context.Database.OpenConnection();
        context.Database.EnsureCreated();

        var ext = new ExternalSystemDefinition("Erp", "https://erp.example.com", "None");
        context.ExternalSystemDefinitions.Add(ext);

        await context.SaveChangesAsync();

        Assert.True(ext.Id > 0);
    }

    [Fact]
    public async Task ProviderConstructor_WritingSecretColumn_StillSucceeds()
    {
        // Sanity check: the gating must not regress the supported runtime path where a
        // real Data Protection provider is supplied.
        using var context = new ScadaBridgeDbContext(SqliteOptions(), new EphemeralDataProtectionProvider());
        context.Database.OpenConnection();
        context.Database.EnsureCreated();

        var ext = new ExternalSystemDefinition("Erp", "https://erp.example.com", "ApiKey")
        {
            AuthConfiguration = "{\"apiKey\":\"live-secret\"}"
        };
        context.ExternalSystemDefinitions.Add(ext);

        await context.SaveChangesAsync();
        context.ChangeTracker.Clear();

        var loaded = await context.ExternalSystemDefinitions.SingleAsync(e => e.Id == ext.Id);
        Assert.Equal("{\"apiKey\":\"live-secret\"}", loaded.AuthConfiguration);
    }
}
