using Microsoft.EntityFrameworkCore; using Npgsql; using WorkClub.Application.Clubs.DTOs; using WorkClub.Domain.Entities; using WorkClub.Infrastructure.Data; namespace WorkClub.Api.Services; public class AdminClubService { private readonly AppDbContext _context; private readonly IHttpContextAccessor _httpContextAccessor; public AdminClubService(AppDbContext context, IHttpContextAccessor httpContextAccessor) { _context = context; _httpContextAccessor = httpContextAccessor; } public async Task> GetAllClubsAsync() { var strategy = _context.Database.CreateExecutionStrategy(); return await strategy.ExecuteAsync(async () => { await using var transaction = await _context.Database.BeginTransactionAsync(); await _context.Database.ExecuteSqlRawAsync("SET LOCAL ROLE app_admin"); var clubs = await _context.Clubs.ToListAsync(); await _context.Database.ExecuteSqlRawAsync("RESET ROLE"); await transaction.CommitAsync(); return clubs.Select(c => new ClubDetailDto( c.Id, c.Name, c.SportType.ToString(), c.Description, c.CreatedAt, c.UpdatedAt)).ToList(); }); } public async Task CreateClubAsync(CreateClubRequest request) { var tenantId = "club-" + Guid.NewGuid().ToString().Substring(0, 8); // Ensure interceptors can see the new tenantId var httpContext = _httpContextAccessor.HttpContext; if (httpContext != null) { httpContext.Items["TenantId"] = tenantId; } var club = new Club { Id = Guid.NewGuid(), TenantId = tenantId, Name = request.Name, SportType = request.SportType, Description = request.Description, CreatedAt = DateTimeOffset.UtcNow, UpdatedAt = DateTimeOffset.UtcNow }; var strategy = _context.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { await using var transaction = await _context.Database.BeginTransactionAsync(); await _context.Database.ExecuteSqlRawAsync("SET LOCAL ROLE app_admin"); _context.Clubs.Add(club); await _context.SaveChangesAsync(); await _context.Database.ExecuteSqlRawAsync("RESET ROLE"); await transaction.CommitAsync(); }); return new ClubDetailDto(club.Id, club.Name, club.SportType.ToString(), club.Description, club.CreatedAt, club.UpdatedAt); } public async Task<(ClubDetailDto? club, string? error)> UpdateClubAsync(Guid id, UpdateClubRequest request) { var strategy = _context.Database.CreateExecutionStrategy(); return await strategy.ExecuteAsync<(ClubDetailDto? club, string? error)>(async () => { await using var transaction = await _context.Database.BeginTransactionAsync(); await _context.Database.ExecuteSqlRawAsync("SET LOCAL ROLE app_admin"); var club = await _context.Clubs.FindAsync(id); if (club == null) { await _context.Database.ExecuteSqlRawAsync("RESET ROLE"); return (null, "Club not found"); } club.Name = request.Name; club.SportType = request.SportType; club.Description = request.Description; club.UpdatedAt = DateTimeOffset.UtcNow; await _context.SaveChangesAsync(); await _context.Database.ExecuteSqlRawAsync("RESET ROLE"); await transaction.CommitAsync(); return (new ClubDetailDto(club.Id, club.Name, club.SportType.ToString(), club.Description, club.CreatedAt, club.UpdatedAt), null); }); } public async Task DeleteClubAsync(Guid id) { var strategy = _context.Database.CreateExecutionStrategy(); return await strategy.ExecuteAsync(async () => { await using var transaction = await _context.Database.BeginTransactionAsync(); await _context.Database.ExecuteSqlRawAsync("SET LOCAL ROLE app_admin"); var club = await _context.Clubs.FindAsync(id); if (club == null) { await _context.Database.ExecuteSqlRawAsync("RESET ROLE"); return false; } _context.Clubs.Remove(club); await _context.SaveChangesAsync(); await _context.Database.ExecuteSqlRawAsync("RESET ROLE"); await transaction.CommitAsync(); return true; }); } }