using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Testcontainers.PostgreSql;
using TrackQrApi.Data;
using TrackQrApi.Models;

namespace TrackQrApi.Tests;

public sealed class ApiWebApplicationFactory : WebApplicationFactory<Program>, IAsyncLifetime
{
    private readonly PostgreSqlContainer _postgres = new PostgreSqlBuilder("postgres:latest")
        .Build();

    private bool _containerStarted;

    public async Task InitializeAsync()
    {
        // Ensure container is started (might already be started from ConfigureWebHost)
        EnsureContainerStarted();

        // Run migrations
        using var scope = Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        await db.Database.MigrateAsync();
    }

    public new async Task DisposeAsync()
    {
        await _postgres.DisposeAsync();
        await base.DisposeAsync();
    }

    private void EnsureContainerStarted()
    {
        if (!_containerStarted)
        {
            _postgres.StartAsync().GetAwaiter().GetResult();
            _containerStarted = true;
        }
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        // Ensure container is started before we need the connection string
        EnsureContainerStarted();

        builder.UseEnvironment("Testing");

        // Set environment variables for configuration (these take precedence)
        Environment.SetEnvironmentVariable("Jwt__Secret", "test-secret-key-min-32-characters-long-for-hmac256!");
        Environment.SetEnvironmentVariable("Jwt__Issuer", "TrakQR");
        Environment.SetEnvironmentVariable("Jwt__Audience", "TrakQR");
        Environment.SetEnvironmentVariable("Jwt__ExpirationMinutes", "60");
        Environment.SetEnvironmentVariable("Email__Provider", "console");
        Environment.SetEnvironmentVariable("Stripe__SecretKey", "sk_test_fake_key");
        Environment.SetEnvironmentVariable("Stripe__WebhookSecret", "whsec_fake_secret");
        Environment.SetEnvironmentVariable("Stripe__ProPriceId", "price_test_pro");
        Environment.SetEnvironmentVariable("Stripe__BusinessPriceId", "price_test_business");
        Environment.SetEnvironmentVariable("ConnectionStrings__PostgresConnection", _postgres.GetConnectionString());

        builder.ConfigureTestServices(services =>
        {
            // Remove existing DbContext registration
            var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));

            if (descriptor != null) services.Remove(descriptor);

            // Add DbContext with Testcontainers connection string
            services.AddDbContext<AppDbContext>(options =>
                options.UseNpgsql(_postgres.GetConnectionString()));
        });
    }

    /// <summary>
    ///     Upgrades a workspace to Pro plan for testing features that require paid plans.
    /// </summary>
    public async Task UpgradeWorkspaceToPro(Guid workspaceId)
    {
        using var scope = Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        var workspace = await db.Workspaces.FindAsync(workspaceId);
        if (workspace != null)
        {
            workspace.Plan = WorkspacePlan.Pro;
            await db.SaveChangesAsync();
        }
    }
}