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<List<ClubDetailDto>> 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<ClubDetailDto> 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<bool> DeleteClubAsync(Guid id)
    {
        var strategy = _context.Database.CreateExecutionStrategy();
        return await strategy.ExecuteAsync<bool>(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;
        });
    }
}
