using System.Net; using System.Net.Http.Json; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using WorkClub.Domain.Entities; using WorkClub.Domain.Enums; using WorkClub.Infrastructure.Data; using WorkClub.Tests.Integration.Infrastructure; using Xunit; namespace WorkClub.Tests.Integration.Clubs; public class ClubEndpointsTests : IntegrationTestBase { public ClubEndpointsTests(CustomWebApplicationFactory factory) : base(factory) { } public override async Task InitializeAsync() { using var scope = Factory.Services.CreateScope(); var context = scope.ServiceProvider.GetRequiredService(); // Clean up and setup test data context.Clubs.RemoveRange(context.Clubs); context.Members.RemoveRange(context.Members); await context.SaveChangesAsync(); // Create test clubs var club1Id = Guid.NewGuid(); var club2Id = Guid.NewGuid(); var club1 = new Club { Id = club1Id, TenantId = "tenant1", Name = "Test Tennis Club", SportType = SportType.Tennis, Description = "Test club 1", CreatedAt = DateTimeOffset.UtcNow, UpdatedAt = DateTimeOffset.UtcNow }; var club2 = new Club { Id = club2Id, TenantId = "tenant2", Name = "Test Cycling Club", SportType = SportType.Cycling, Description = "Test club 2", CreatedAt = DateTimeOffset.UtcNow, UpdatedAt = DateTimeOffset.UtcNow }; context.Clubs.AddRange(club1, club2); // Create test members (membership links) var adminUserId = "admin-user-id"; var managerUserId = "manager-user-id"; // Admin is member of both clubs context.Members.Add(new Member { Id = Guid.NewGuid(), TenantId = "tenant1", ExternalUserId = adminUserId, DisplayName = "Admin User", Email = "admin@test.com", Role = ClubRole.Admin, ClubId = club1Id, CreatedAt = DateTimeOffset.UtcNow, UpdatedAt = DateTimeOffset.UtcNow }); context.Members.Add(new Member { Id = Guid.NewGuid(), TenantId = "tenant2", ExternalUserId = adminUserId, DisplayName = "Admin User", Email = "admin@test.com", Role = ClubRole.Member, ClubId = club2Id, CreatedAt = DateTimeOffset.UtcNow, UpdatedAt = DateTimeOffset.UtcNow }); // Manager is only member of club1 context.Members.Add(new Member { Id = Guid.NewGuid(), TenantId = "tenant1", ExternalUserId = managerUserId, DisplayName = "Manager User", Email = "manager@test.com", Role = ClubRole.Manager, ClubId = club1Id, CreatedAt = DateTimeOffset.UtcNow, UpdatedAt = DateTimeOffset.UtcNow }); await context.SaveChangesAsync(); } [Fact] public async Task GetClubsMe_ReturnsOnlyUserClubs() { // Arrange - admin is member of 2 clubs SetTenant("tenant1"); AuthenticateAs("admin@test.com", new Dictionary { ["tenant1"] = "Admin", ["tenant2"] = "Member" }, userId: "admin-user-id"); // Act var response = await Client.GetAsync("/api/clubs/me"); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); var clubs = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(clubs); Assert.Equal(2, clubs.Count); Assert.Contains(clubs, c => c.Name == "Test Tennis Club"); Assert.Contains(clubs, c => c.Name == "Test Cycling Club"); } [Fact] public async Task GetClubsMe_ForManagerUser_ReturnsOnlyOneClub() { // Arrange - manager is only member of club1 SetTenant("tenant1"); AuthenticateAs("manager@test.com", new Dictionary { ["tenant1"] = "Manager" }, userId: "manager-user-id"); // Act var response = await Client.GetAsync("/api/clubs/me"); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); var clubs = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(clubs); Assert.Single(clubs); Assert.Equal("Test Tennis Club", clubs[0].Name); } [Fact] public async Task GetClubsCurrent_ReturnsCurrentTenantClub() { // Arrange SetTenant("tenant1"); AuthenticateAs("admin@test.com", new Dictionary { ["tenant1"] = "Admin" }, userId: "admin-user-id"); // Act var response = await Client.GetAsync("/api/clubs/current"); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); var club = await response.Content.ReadFromJsonAsync(); Assert.NotNull(club); Assert.Equal("Test Tennis Club", club.Name); Assert.Equal("Tennis", club.SportType); Assert.Equal("Test club 1", club.Description); } [Fact] public async Task GetClubsCurrent_DifferentTenant_ReturnsDifferentClub() { // Arrange SetTenant("tenant2"); AuthenticateAs("admin@test.com", new Dictionary { ["tenant2"] = "Member" }, userId: "admin-user-id"); // Act var response = await Client.GetAsync("/api/clubs/current"); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); var club = await response.Content.ReadFromJsonAsync(); Assert.NotNull(club); Assert.Equal("Test Cycling Club", club.Name); Assert.Equal("Cycling", club.SportType); } [Fact] public async Task GetClubsCurrent_NoTenantContext_ReturnsBadRequest() { // Arrange - no tenant header set AuthenticateAs("admin@test.com", new Dictionary { ["tenant1"] = "Admin" }, userId: "admin-user-id"); // Act var response = await Client.GetAsync("/api/clubs/current"); // Assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } [Fact] public async Task GetClubsMe_Unauthenticated_ReturnsUnauthorized() { // Act var response = await Client.GetAsync("/api/clubs/me"); // Assert Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); } } // Response DTOs for test assertions public record ClubListResponse(Guid Id, string Name, string SportType, int MemberCount); public record ClubDetailResponse(Guid Id, string Name, string SportType, string? Description, DateTimeOffset CreatedAt);