using ScadaLink.ConfigurationDatabase;

namespace ScadaLink.ConfigurationDatabase.Tests;

public class DesignTimeDbContextFactoryTests : IDisposable
{
    private const string EnvVar = "SCADALINK_DESIGNTIME_CONNECTIONSTRING";
    private readonly string? _originalEnv;

    public DesignTimeDbContextFactoryTests()
    {
        _originalEnv = Environment.GetEnvironmentVariable(EnvVar);
    }

    public void Dispose()
    {
        Environment.SetEnvironmentVariable(EnvVar, _originalEnv);
    }

    [Fact]
    public void CreateDbContext_NoConnectionStringConfigured_ThrowsClearException()
    {
        // Regression guard for ConfigurationDatabase-002: the factory must not fall back
        // to a hardcoded `sa`/password literal. With nothing configured it must fail loudly
        // with an actionable message instead of silently pointing tooling at a guessed DB.
        Environment.SetEnvironmentVariable(EnvVar, null);
        var factory = new DesignTimeDbContextFactory();

        var ex = Assert.Throws<InvalidOperationException>(() => factory.CreateDbContext(Array.Empty<string>()));

        Assert.Contains("connection string", ex.Message, StringComparison.OrdinalIgnoreCase);
        // The message must not leak / suggest a hardcoded `sa` credential.
        Assert.DoesNotContain("sa", ex.Message.Split(' '), StringComparer.OrdinalIgnoreCase);
    }

    [Fact]
    public void CreateDbContext_ConnectionStringFromEnvironmentVariable_IsUsed()
    {
        // The design-time connection string may be supplied via an environment variable
        // rather than a source literal.
        Environment.SetEnvironmentVariable(EnvVar,
            "Server=localhost,1433;Database=ScadaLink_Config;Trusted_Connection=True;TrustServerCertificate=True");
        var factory = new DesignTimeDbContextFactory();

        using var context = factory.CreateDbContext(Array.Empty<string>());

        Assert.NotNull(context);
    }

    [Fact]
    public void DesignTimeDbContextFactory_SourceContainsNoHardcodedSaCredential()
    {
        // Belt-and-braces: assert no `sa`/password literal exists in the compiled type's
        // behaviour by confirming the no-config path throws rather than connecting.
        Environment.SetEnvironmentVariable(EnvVar, null);
        var factory = new DesignTimeDbContextFactory();

        var ex = Assert.Throws<InvalidOperationException>(() => factory.CreateDbContext(Array.Empty<string>()));
        Assert.DoesNotContain("YourPassword", ex.Message);
    }
}
