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<List<ClubListDto>> GetMyClubsAsync()
    {
        var clubsClaim = _httpContextAccessor.HttpContext?.User.FindFirst("clubs")?.Value;
        if (string.IsNullOrEmpty(clubsClaim))
        {
            return new List<ClubListDto>();
        }

        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<ClubListDto>();
        }

        var clubDtos = new List<ClubListDto>();
        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<ClubDetailDto?> 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
        );
    }
}
