// EN: HTTP context-based tenant provider implementation.
// VI: Implementation tenant provider dựa trên HTTP context.

using System.Security.Claims;

namespace InventoryService.API.Infrastructure.Tenant;

/// <summary>
/// EN: Extracts tenant context from JWT claims and HTTP headers.
/// VI: Trích xuất tenant context từ JWT claims và HTTP headers.
/// </summary>
public class HttpContextTenantProvider : ITenantProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly ILogger<HttpContextTenantProvider> _logger;

    private const string ServiceCallHeader = "X-Service-Call";
    private const string ShopIdHeader = "X-Shop-Id";
    private const string ServiceCallSecret = "internal";

    public HttpContextTenantProvider(
        IHttpContextAccessor httpContextAccessor,
        ILogger<HttpContextTenantProvider> logger)
    {
        _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public Guid? GetCurrentUserId()
    {
        var claim = GetClaim(ClaimTypes.NameIdentifier) ?? GetClaim("sub");
        if (claim != null && Guid.TryParse(claim, out var userId))
            return userId;
        return null;
    }

    public Guid? GetCurrentMerchantId()
    {
        var claim = GetClaim("merchant_id");
        if (claim != null && Guid.TryParse(claim, out var merchantId))
            return merchantId;
        return null;
    }

    public Guid? GetCurrentShopId()
    {
        var claim = GetClaim("shop_id");
        if (claim != null && Guid.TryParse(claim, out var shopId))
            return shopId;

        var headerValue = _httpContextAccessor.HttpContext?.Request.Headers[ShopIdHeader].FirstOrDefault();
        if (headerValue != null && Guid.TryParse(headerValue, out var headerShopId))
            return headerShopId;

        return null;
    }

    public bool IsServiceCall()
    {
        var headerValue = _httpContextAccessor.HttpContext?.Request.Headers[ServiceCallHeader].FirstOrDefault();
        return string.Equals(headerValue, ServiceCallSecret, StringComparison.OrdinalIgnoreCase);
    }

    public bool IsAdmin()
    {
        var roles = _httpContextAccessor.HttpContext?.User
            .FindAll(ClaimTypes.Role)
            .Select(c => c.Value)
            .ToList() ?? [];

        var customRoles = _httpContextAccessor.HttpContext?.User
            .FindAll("role")
            .Select(c => c.Value)
            .ToList() ?? [];

        roles.AddRange(customRoles);

        return roles.Any(r => r.Equals("admin", StringComparison.OrdinalIgnoreCase)
            || r.Equals("system", StringComparison.OrdinalIgnoreCase)
            || r.Equals("superadmin", StringComparison.OrdinalIgnoreCase));
    }

    private string? GetClaim(string claimType)
    {
        return _httpContextAccessor.HttpContext?.User.FindFirst(claimType)?.Value;
    }
}
