namespace GmRelay.Bot.Tests.Web;

public sealed class ClubMembershipsTests
{
    [Fact]
    public async Task SessionStore_ShouldExposeMembershipMethods()
    {
        var sessionStore = await ReadRepositoryFileAsync("src/GmRelay.Web/Services/ISessionStore.cs");

        Assert.Contains("ApplyForMembershipAsync", sessionStore, StringComparison.Ordinal);
        Assert.Contains("ApproveMembershipAsync", sessionStore, StringComparison.Ordinal);
        Assert.Contains("RejectMembershipAsync", sessionStore, StringComparison.Ordinal);
        Assert.Contains("LeaveClubMembershipAsync", sessionStore, StringComparison.Ordinal);
        Assert.Contains("GetPendingApplicationsAsync", sessionStore, StringComparison.Ordinal);
        Assert.Contains("GetMembershipsForPlayerAsync", sessionStore, StringComparison.Ordinal);
        Assert.Contains("IsActiveClubMemberAsync", sessionStore, StringComparison.Ordinal);
        Assert.Contains("GetGroupIdForMembershipAsync", sessionStore, StringComparison.Ordinal);
    }

    [Fact]
    public async Task SessionService_ShouldFilterPublicSessionsWithMemberAwareClause()
    {
        var service = await ReadRepositoryFileAsync("src/GmRelay.Web/Services/SessionService.cs");

        // Member-aware: ClubOnly only visible to Active members
        Assert.Contains("publication_mode = 'ClubOnly'", service, StringComparison.Ordinal);
        Assert.Contains("club_memberships", service, StringComparison.Ordinal);
        Assert.Contains("cm.status = 'Active'", service, StringComparison.Ordinal);
    }

    [Fact]
    public async Task AuthorizedMembershipService_ShouldValidateCallerForGmActions()
    {
        var service = await ReadRepositoryFileAsync("src/GmRelay.Web/Services/AuthorizedMembershipService.cs");

        Assert.Contains("IsGroupManagerAsync", service, StringComparison.Ordinal);
        Assert.Contains("ApproveForCurrentGmAsync", service, StringComparison.Ordinal);
        Assert.Contains("RejectForCurrentGmAsync", service, StringComparison.Ordinal);
        Assert.Contains("SessionAccessDeniedException", service, StringComparison.Ordinal);
    }

    [Fact]
    public async Task MyClubMembershipsPage_ShouldRenderLeaveAndCancelButtons()
    {
        var page = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/MyClubMemberships.razor");

        Assert.Contains("@page \"/profile/memberships\"", page, StringComparison.Ordinal);
        Assert.Contains("[Authorize]", page, StringComparison.Ordinal);
        Assert.Contains("Покинуть клуб", page, StringComparison.Ordinal);
        Assert.Contains("Отозвать заявку", page, StringComparison.Ordinal);
        Assert.Contains("Active", page, StringComparison.Ordinal);
        Assert.Contains("Pending", page, StringComparison.Ordinal);
    }

    [Fact]
    public async Task ClubApplicationsPage_ShouldRenderApproveAndReject()
    {
        var page = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/ClubApplications.razor");

        Assert.Contains("/applications", page, StringComparison.Ordinal);
        Assert.Contains("[Authorize]", page, StringComparison.Ordinal);
        Assert.Contains("Одобрить", page, StringComparison.Ordinal);
        Assert.Contains("Отклонить", page, StringComparison.Ordinal);
    }

    [Fact]
    public async Task PublicClubPage_ShouldExposeApplicationCtaAndMembersOnlyBlock()
    {
        var page = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/PublicClub.razor");

        Assert.Contains("viewerPlayerId", page, StringComparison.Ordinal);
        Assert.Contains("Подать заявку", page, StringComparison.Ordinal);
        Assert.Contains("Войти как участник", page, StringComparison.Ordinal);
        Assert.Contains("Игры для участников клуба", page, StringComparison.Ordinal);
        Assert.Contains("ApplyForCurrentUserAsync", page, 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}'.");
    }
}
