using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;

namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase;

/// <summary>
/// Factory for creating DbContext instances at design time (used by dotnet ef tooling).
/// Resolves the connection string from the Host's appsettings files, or — for environments
/// where those files are not present — from the
/// <c>SCADABRIDGE_DESIGNTIME_CONNECTIONSTRING</c> environment variable.
/// </summary>
/// <remarks>
/// There is deliberately no hardcoded fallback connection string. A credential literal in
/// source is committed to version control, encourages copy-paste of <c>sa</c> /
/// <c>TrustServerCertificate=True</c> into real environments, and can silently point
/// <c>dotnet ef</c> tooling at an unintended database. If no connection string can be
/// resolved, this factory fails loudly with an actionable message.
/// </remarks>
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ScadaBridgeDbContext>
{
    private const string EnvironmentVariableName = "SCADABRIDGE_DESIGNTIME_CONNECTIONSTRING";
    private const string ConfigurationKey = "ScadaBridge:Database:ConfigurationDb";

    /// <summary>
    /// Creates a <see cref="ScadaBridgeDbContext"/> for design-time EF Core tooling.
    /// </summary>
    /// <param name="args">Arguments passed by the EF tooling (unused).</param>
    /// <returns>A configured <see cref="ScadaBridgeDbContext"/> pointing at the resolved connection string.</returns>
    public ScadaBridgeDbContext CreateDbContext(string[] args)
    {
        var configurationBuilder = new ConfigurationBuilder();

        // The Host's appsettings files are an optional source — only wire them up when the
        // Host directory actually exists, otherwise SetBasePath throws DirectoryNotFoundException
        // (e.g. when this factory is exercised from a test runner with no sibling Host folder).
        var hostDirectory = Path.Combine(Directory.GetCurrentDirectory(), "..", "ZB.MOM.WW.ScadaBridge.Host");
        if (Directory.Exists(hostDirectory))
        {
            configurationBuilder
                .SetBasePath(hostDirectory)
                .AddJsonFile("appsettings.json", optional: true)
                .AddJsonFile("appsettings.Central.json", optional: true);
        }

        var configuration = configurationBuilder.Build();

        var connectionString = configuration[ConfigurationKey]
            ?? Environment.GetEnvironmentVariable(EnvironmentVariableName);

        if (string.IsNullOrWhiteSpace(connectionString))
        {
            throw new InvalidOperationException(
                "No design-time database connection string was found. Set the configuration " +
                $"key '{ConfigurationKey}' in the Host's appsettings file, or set the " +
                $"'{EnvironmentVariableName}' environment variable, before running dotnet ef tooling.");
        }

        var optionsBuilder = new DbContextOptionsBuilder<ScadaBridgeDbContext>();
        optionsBuilder.UseSqlServer(connectionString);

        return new ScadaBridgeDbContext(optionsBuilder.Options);
    }
}
