using System.ComponentModel.DataAnnotations;
using Asp.Versioning;
using Baya.Application.Features.Bnpl.Commands.InitiateBnplOrder;
using Baya.Application.Features.Bnpl.Queries.CheckBnplEligibility;
using Baya.Application.Features.Bnpl.Queries.GetBnplOrderByRequest;
using Baya.Application.Features.Bnpl.Queries.GetBnplOrderStatus;
using Baya.Application.Models.Bnpl;
using Baya.WebFramework.Attributes;
using Baya.WebFramework.BaseController;
using Baya.WebFramework.ServiceConfiguration;
using Mediator;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;

namespace Baya.Web.Api.Controllers.V1;

/// <summary>
/// The customer-facing BNPL checkout — the "pay with installments" alternative to the card path. Eligibility
/// records the plan on a <c>bnpl_transactions</c> row; initiate issues the provider token + redirect. Both are
/// tenancy-scoped to the caller and rate-limited as money endpoints. The order amount is always the request's
/// frozen gross — never client-supplied.
/// </summary>
[ApiVersion("1")]
[ApiController]
[Route("api/v{version:apiVersion}/checkout_bnpl")]
[Authorize]
[EnableRateLimiting(RateLimitingServiceExtension.SensitivePolicy)]
[Display(Description = "Customer BNPL checkout (eligibility + initiate)")]
public sealed class CheckoutBnplController(ISender sender) : BaseController
{
    [HttpPost("[action]")]
    [ProducesOkApiResponseType<BnplEligibilityDto>]
    public async Task<IActionResult> Eligibility(CheckBnplEligibilityQuery query, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(query, cancellationToken));

    [HttpPost("[action]")]
    [ProducesOkApiResponseType<InitiateBnplResult>]
    public async Task<IActionResult> Initiate(InitiateBnplBody body, CancellationToken cancellationToken)
    {
        var idempotencyKey = Request.Headers["Idempotency-Key"].FirstOrDefault();
        return OperationResult(await sender.Send(
            new InitiateBnplOrderCommand(body.BookingRequestId, body.ProviderCode, idempotencyKey), cancellationToken));
    }

    [HttpGet("{id:long}")]
    [ProducesOkApiResponseType<BnplOrderStatusDto>]
    public async Task<IActionResult> Get(long id, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new GetBnplOrderStatusQuery(id, AdminView: false), cancellationToken));

    // Reach the BNPL order from the booking request id (the return-poll holds the request id, not the order id).
    [HttpGet("by_request/{bookingRequestId}")]
    [ProducesOkApiResponseType<BnplOrderStatusDto>]
    public async Task<IActionResult> ByRequest(long bookingRequestId, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new GetBnplOrderByRequestQuery(bookingRequestId), cancellationToken));

    /// <summary>The initiate body (the idempotency key comes from the <c>Idempotency-Key</c> header).</summary>
    public record InitiateBnplBody(long BookingRequestId, string ProviderCode);
}
