using Microsoft.AspNetCore.Mvc;

namespace WebClientTpos.Server.Infrastructure;

/// <summary>
/// EN: DelegatingHandler that attaches a Bearer token to outgoing microservice requests.
///     Priority: (1) httpOnly session cookie → (2) forwarded Authorization header (legacy fallback).
///     With cookie-based BFF auth (SEC-W-01), WASM never sends raw tokens — they live in httpOnly cookies.
/// VI: DelegatingHandler đính kèm Bearer token vào request gửi đi đến microservice.
///     Ưu tiên: (1) httpOnly session cookie → (2) forwarding Authorization header (fallback cũ).
///     Với cookie-based BFF auth (SEC-W-01), WASM không bao giờ gửi token thô — chúng ở trong httpOnly cookie.
/// </summary>
public class AuthForwardingHandler : DelegatingHandler
{
    // EN: Must match BffAuthController.SessionCookieName.
    // VI: Phải khớp với BffAuthController.SessionCookieName.
    private const string SessionCookieName = "bff_session";

    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly ILogger<AuthForwardingHandler> _logger;

    public AuthForwardingHandler(IHttpContextAccessor httpContextAccessor, ILogger<AuthForwardingHandler> logger)
    {
        _httpContextAccessor = httpContextAccessor;
        _logger = logger;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var context = _httpContextAccessor.HttpContext;
        if (context == null)
        {
            _logger.LogWarning("EN: HttpContext is null — cannot forward auth for {Uri}.", request.RequestUri);
            return base.SendAsync(request, cancellationToken);
        }

        // EN: (1) Prefer httpOnly session cookie — set by BffAuthController.Login().
        //         This is the secure path: WASM never handled the raw token.
        // VI: (1) Ưu tiên httpOnly session cookie — được set bởi BffAuthController.Login().
        //         Đây là con đường bảo mật: WASM không bao giờ xử lý token thô.
        if (context.Request.Cookies.TryGetValue(SessionCookieName, out var sessionToken)
            && !string.IsNullOrEmpty(sessionToken))
        {
            request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {sessionToken}");
            _logger.LogDebug("EN: Auth attached from httpOnly session cookie for {Uri}.", request.RequestUri);
            return base.SendAsync(request, cancellationToken);
        }

        // EN: (2) Legacy fallback — forward Authorization header sent by WASM client.
        //         Used during transition before all clients migrate to cookie-based auth.
        // VI: (2) Fallback cũ — forwarding Authorization header do WASM client gửi.
        //         Dùng trong thời gian chuyển tiếp trước khi tất cả client chuyển sang cookie-based auth.
        if (context.Request.Headers.TryGetValue("Authorization", out var authHeader)
            && !string.IsNullOrEmpty(authHeader.ToString()))
        {
            request.Headers.TryAddWithoutValidation("Authorization", authHeader.ToString());
            _logger.LogDebug("EN: Auth header forwarded from client (legacy) for {Uri}.", request.RequestUri);
            return base.SendAsync(request, cancellationToken);
        }

        _logger.LogWarning("EN: No auth found (no session cookie, no Authorization header) for {Uri}.", request.RequestUri);
        return base.SendAsync(request, cancellationToken);
    }
}

/// <summary>
/// EN: Extension methods for proxying HttpResponseMessage to IActionResult.
/// VI: Extension methods để proxy HttpResponseMessage thành IActionResult.
/// </summary>
public static class HttpProxyExtensions
{
    /// <summary>
    /// EN: Proxy an HttpResponseMessage to an IActionResult, preserving status code and content.
    /// VI: Proxy HttpResponseMessage thành IActionResult, giữ nguyên status code và content.
    /// </summary>
    public static async Task<IActionResult> ProxyAsync(this Task<HttpResponseMessage> responseTask)
    {
        var response = await responseTask;
        return await response.ToActionResultAsync();
    }

    /// <summary>
    /// EN: Convert an already-awaited HttpResponseMessage to IActionResult.
    /// VI: Chuyển đổi HttpResponseMessage đã await thành IActionResult.
    /// </summary>
    public static async Task<IActionResult> ToActionResultAsync(this HttpResponseMessage response)
    {
        var content = await response.Content.ReadAsStringAsync();
        return new ContentResult
        {
            StatusCode = (int)response.StatusCode,
            Content = content,
            ContentType = response.Content.Headers.ContentType?.ToString() ?? "application/json"
        };
    }
}
