using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using WorkClub.Domain.Enums;
using WorkClub.Infrastructure.Data;

namespace WorkClub.Api.Auth;

public class ClubRoleClaimsTransformation : IClaimsTransformation
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly AppDbContext _context;

    public ClubRoleClaimsTransformation(
        IHttpContextAccessor httpContextAccessor,
        AppDbContext context)
    {
        _httpContextAccessor = httpContextAccessor;
        _context = context;
    }

    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        if (principal.Identity is not ClaimsIdentity identity || !identity.IsAuthenticated)
        {
            return Task.FromResult(principal);
        }

        var clubsClaim = principal.FindFirst("clubs")?.Value;
        if (string.IsNullOrEmpty(clubsClaim))
        {
            return Task.FromResult(principal);
        }

        // Parse comma-separated club UUIDs
        var clubIds = clubsClaim.Split(',', StringSplitOptions.RemoveEmptyEntries)
            .Select(id => id.Trim())
            .ToArray();

        if (clubIds.Length == 0)
        {
            return Task.FromResult(principal);
        }

        var tenantId = _httpContextAccessor.HttpContext?.Request.Headers["X-Tenant-Id"].FirstOrDefault();
        if (string.IsNullOrEmpty(tenantId) || !clubIds.Contains(tenantId))
        {
            return Task.FromResult(principal);
        }

        var userIdClaim = principal.FindFirst("preferred_username")?.Value;
        if (string.IsNullOrEmpty(userIdClaim))
        {
            return Task.FromResult(principal);
        }

        // Look up the user's role in the database for the requested tenant
        _httpContextAccessor.HttpContext!.Items["TenantId"] = tenantId;
        var memberRole = GetMemberRole(userIdClaim, tenantId);
        if (memberRole.HasValue)
        {
            var mappedRole = MapClubRoleToAspNetRole(memberRole.Value);
            identity.AddClaim(new Claim(ClaimTypes.Role, mappedRole));
        }

        return Task.FromResult(principal);
    }

    private ClubRole? GetMemberRole(string externalUserId, string tenantId)
    {
        try
        {
            var member = _context.Members
                .FirstOrDefault(m => m.Email == externalUserId && m.TenantId == tenantId);

            return member?.Role;
        }
        catch
        {
            return null;
        }
    }

    private static string MapClubRoleToAspNetRole(ClubRole clubRole)
    {
        return clubRole switch
        {
            ClubRole.Admin => "Admin",
            ClubRole.Manager => "Manager",
            ClubRole.Member => "Member",
            ClubRole.Viewer => "Viewer",
            _ => "Viewer"
        };
    }
}
