using Microsoft.EntityFrameworkCore; using Npgsql; using WorkClub.Application.Clubs.DTOs; using WorkClub.Application.Interfaces; using WorkClub.Domain.Enums; using WorkClub.Infrastructure.Data; namespace WorkClub.Api.Services; public class ClubService { private readonly AppDbContext _context; private readonly ITenantProvider _tenantProvider; private readonly IHttpContextAccessor _httpContextAccessor; public ClubService( AppDbContext context, ITenantProvider tenantProvider, IHttpContextAccessor httpContextAccessor) { _context = context; _tenantProvider = tenantProvider; _httpContextAccessor = httpContextAccessor; } public async Task> GetMyClubsAsync() { var clubsClaim = _httpContextAccessor.HttpContext?.User.FindFirst("clubs")?.Value; if (string.IsNullOrEmpty(clubsClaim)) { return new List(); } var tenantIds = clubsClaim.Split(',', StringSplitOptions.RemoveEmptyEntries) .Select(t => t.Trim()) .Where(t => !string.IsNullOrEmpty(t) && Guid.TryParse(t, out _)) .ToList(); if (tenantIds.Count == 0) { return new List(); } var clubDtos = new List(); var connectionString = _context.Database.GetConnectionString(); foreach (var tenantId in tenantIds) { await using var connection = new NpgsqlConnection(connectionString); await connection.OpenAsync(); await using var transaction = await connection.BeginTransactionAsync(); // Set RLS context using (var command = connection.CreateCommand()) { command.Transaction = transaction; command.CommandText = $"SET LOCAL app.current_tenant_id = '{tenantId}'"; await command.ExecuteNonQueryAsync(); } Guid? clubId = null; string? clubName = null; int? sportTypeInt = null; // Fetch club details using (var command = connection.CreateCommand()) { command.Transaction = transaction; command.CommandText = @" SELECT c.""Id"", c.""Name"", c.""SportType"" FROM clubs AS c WHERE c.""TenantId"" = @tenantId"; var parameter = command.CreateParameter(); parameter.ParameterName = "@tenantId"; parameter.Value = tenantId; command.Parameters.Add(parameter); using (var reader = await command.ExecuteReaderAsync()) { if (await reader.ReadAsync()) { clubId = reader.GetGuid(0); clubName = reader.GetString(1); sportTypeInt = reader.GetInt32(2); } } } // Fetch member count if club exists if (clubId.HasValue && clubName != null && sportTypeInt.HasValue) { using (var memberCommand = connection.CreateCommand()) { memberCommand.Transaction = transaction; memberCommand.CommandText = @" SELECT COUNT(*) FROM members AS m WHERE m.""ClubId"" = @clubId"; var param = memberCommand.CreateParameter(); param.ParameterName = "@clubId"; param.Value = clubId; memberCommand.Parameters.Add(param); var memberCountResult = await memberCommand.ExecuteScalarAsync(); var memberCount = memberCountResult != null ? Convert.ToInt32(memberCountResult) : 0; var sportTypeEnum = ((SportType)sportTypeInt.Value).ToString(); clubDtos.Add(new ClubListDto( clubId.Value, clubName, sportTypeEnum, memberCount, Guid.Parse(tenantId) )); } } await transaction.CommitAsync(); } return clubDtos; } public async Task GetCurrentClubAsync() { var tenantId = _tenantProvider.GetTenantId(); var club = await _context.Clubs .FirstOrDefaultAsync(c => c.TenantId == tenantId); if (club == null) return null; return new ClubDetailDto( club.Id, club.Name, club.SportType.ToString(), club.Description, club.CreatedAt, club.UpdatedAt ); } }