namespace GmRelay.Bot.Tests.Web;

public sealed class PublicationModeTests
{
    [Fact]
    public void PublicationMode_ShouldHaveFourValues()
    {
        var values = Enum.GetValues<GmRelay.Shared.Domain.PublicationMode>();
        Assert.Equal(4, values.Length);
        Assert.Contains(GmRelay.Shared.Domain.PublicationMode.None, values);
        Assert.Contains(GmRelay.Shared.Domain.PublicationMode.Catalog, values);
        Assert.Contains(GmRelay.Shared.Domain.PublicationMode.ClubOnly, values);
        Assert.Contains(GmRelay.Shared.Domain.PublicationMode.Both, values);
    }

    [Fact]
    public async Task MigrationV030_ShouldAddClubMembershipsTable()
    {
        var migration = await ReadRepositoryFileAsync("src/GmRelay.Bot/Migrations/V030__add_club_memberships_and_publication_mode.sql");

        Assert.Contains("CREATE TABLE club_memberships", migration, StringComparison.Ordinal);
        Assert.Contains("status", migration, StringComparison.Ordinal);
        Assert.Contains("role", migration, StringComparison.Ordinal);
        Assert.Contains("Pending", migration, StringComparison.Ordinal);
        Assert.Contains("Active", migration, StringComparison.Ordinal);
        Assert.Contains("Rejected", migration, StringComparison.Ordinal);
        Assert.Contains("Left", migration, StringComparison.Ordinal);
        Assert.Contains("ux_club_memberships_one_active", migration, StringComparison.Ordinal);
        Assert.Contains("Member", migration, StringComparison.Ordinal);
    }

    [Fact]
    public async Task MigrationV030_ShouldReplaceIsPublicWithPublicationModeEnum()
    {
        var migration = await ReadRepositoryFileAsync("src/GmRelay.Bot/Migrations/V030__add_club_memberships_and_publication_mode.sql");

        Assert.Contains("ADD COLUMN publication_mode", migration, StringComparison.Ordinal);
        Assert.Contains("ck_sessions_publication_mode", migration, StringComparison.Ordinal);
        Assert.Contains("'None', 'Catalog', 'ClubOnly', 'Both'", migration, StringComparison.Ordinal);
        Assert.Contains("UPDATE sessions SET publication_mode = 'Both' WHERE is_public = true", migration, StringComparison.Ordinal);
        Assert.Contains("UPDATE sessions SET publication_mode = 'None' WHERE is_public = false", migration, StringComparison.Ordinal);
        Assert.Contains("DROP COLUMN is_public", migration, StringComparison.Ordinal);
    }

    [Fact]
    public async Task MigrationV030_ShouldRecreatePartialIndexUsingPublicationMode()
    {
        var migration = await ReadRepositoryFileAsync("src/GmRelay.Bot/Migrations/V030__add_club_memberships_and_publication_mode.sql");

        Assert.Contains("ix_sessions_public_schedule", migration, StringComparison.Ordinal);
        Assert.Contains("publication_mode IN ('Catalog', 'Both')", migration, StringComparison.Ordinal);
    }

    [Fact]
    public async Task MigrationV030_ShouldAddPortfolioPublicationModeColumn()
    {
        var migration = await ReadRepositoryFileAsync("src/GmRelay.Bot/Migrations/V030__add_club_memberships_and_publication_mode.sql");

        Assert.Contains("portfolio_games", migration, StringComparison.Ordinal);
        Assert.Contains("ix_portfolio_games_showcase", migration, StringComparison.Ordinal);
    }

    private static async Task<string> ReadRepositoryFileAsync(string relativePath)
    {
        var directory = new DirectoryInfo(AppContext.BaseDirectory);
        while (directory is not null)
        {
            var candidate = Path.Combine(directory.FullName, relativePath);
            if (File.Exists(candidate))
            {
                return await File.ReadAllTextAsync(candidate);
            }

            directory = directory.Parent;
        }

        throw new FileNotFoundException($"Could not locate repository file '{relativePath}'.");
    }
}
