using Microsoft.Data.SqlClient;

namespace ZB.MOM.WW.Secrets.Replicator.SqlServer.Tests.Live;

/// <summary>
/// Shared connection details for the env-gated live SQL-Server suite.
/// </summary>
/// <remarks>
/// Gated on <c>SECRETS_SQLSERVER_CONNSTR</c> and skips cleanly when it is unset, matching the family
/// live-test idiom — the offline suite must stay runnable on any machine. Set it to a database the
/// test is allowed to create and drop a schema in, for example:
/// <c>Server=10.100.0.35,31433;Database=ZbSecretsTest;User Id=sa;Password=...;TrustServerCertificate=True</c>.
/// </remarks>
public static class LiveSqlServer
{
    /// <summary>Environment variable holding the live connection string.</summary>
    public const string ConnectionStringVariable = "SECRETS_SQLSERVER_CONNSTR";

    /// <summary>The configured connection string, or <see langword="null"/> when the suite is not enabled.</summary>
    public static string? ConnectionString =>
        Environment.GetEnvironmentVariable(ConnectionStringVariable);

    /// <summary>Whether the live suite should run.</summary>
    public static bool IsEnabled => !string.IsNullOrWhiteSpace(ConnectionString);

    /// <summary>Skip reason shown when the suite is not enabled.</summary>
    public const string SkipReason =
        "Live SQL-Server suite disabled; set SECRETS_SQLSERVER_CONNSTR to enable.";

    /// <summary>
    /// Builds options against a throwaway schema so parallel runs and repeat runs cannot collide,
    /// and so a failed run leaves no trace in a shared database.
    /// </summary>
    /// <param name="schemaName">The unique schema name for this test.</param>
    /// <returns>Options targeting that schema.</returns>
    public static SqlServerSecretsOptions OptionsFor(string schemaName) => new()
    {
        ConnectionString = ConnectionString!,
        SchemaName = schemaName,
    };

    /// <summary>Generates a unique, allow-list-legal schema name for one test class.</summary>
    /// <returns>A fresh schema name.</returns>
    public static string NewSchemaName() => $"zbtest_{Guid.NewGuid():N}"[..32];

    /// <summary>Drops the throwaway schema and its tables.</summary>
    /// <param name="schemaName">The schema to drop.</param>
    /// <returns>A task that completes when the schema is gone.</returns>
    public static async Task DropSchemaAsync(string schemaName)
    {
        if (!IsEnabled)
        {
            return;
        }

        await using var connection = new SqlConnection(ConnectionString);
        await connection.OpenAsync();

        await using SqlCommand command = connection.CreateCommand();
        command.CommandText = $"""
            IF OBJECT_ID(N'[{schemaName}].[secret]', N'U') IS NOT NULL DROP TABLE [{schemaName}].[secret];
            IF OBJECT_ID(N'[{schemaName}].[schema_version]', N'U') IS NOT NULL DROP TABLE [{schemaName}].[schema_version];
            IF EXISTS (SELECT 1 FROM sys.schemas WHERE name = N'{schemaName}') EXEC(N'DROP SCHEMA [{schemaName}]');
            """;

        await command.ExecuteNonQueryAsync();
    }
}
