using System.ComponentModel.DataAnnotations;
using Asp.Versioning;
using Baya.Application.Features.Refunds.Commands.ConfirmRefundSettlement;
using Baya.Application.Features.Refunds.Commands.CreateRefund;
using Baya.Application.Features.Refunds.Commands.MarkRefundSettlementFailed;
using Baya.Application.Features.Refunds.Queries.ListRefunds;
using Baya.Application.Models.Common;
using Baya.Application.Models.Refunds;
using Baya.Infrastructure.Identity.Identity.PermissionManager;
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>
/// Admin-only refund console. Creating a refund reverses a captured booking payment across both fee legs, posts
/// the balanced ledger reversal, forks on whether the nurse was already paid (clawback), and is rate-limited as
/// a money endpoint. There is no customer refund-initiation path.
/// </summary>
[ApiVersion("1")]
[ApiController]
[Route("api/v{version:apiVersion}/admin_refunds")]
[Authorize(ConstantPolicies.DynamicPermission)]
[EnableRateLimiting(RateLimitingServiceExtension.SensitivePolicy)]
[Display(Description = "Admin refund creation + worklist")]
public sealed class AdminRefundsController(ISender sender) : BaseController
{
    [HttpPost]
    [ProducesOkApiResponseType<CreateRefundResult>]
    public async Task<IActionResult> Create(CreateRefundCommand command, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(command, cancellationToken));

    [HttpGet]
    [ProducesOkApiResponseType<PagedResult<RefundListItemDto>>]
    public async Task<IActionResult> List([FromQuery] ListRefundsQuery query, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(query, cancellationToken));

    // Reconciliation confirmed the customer cash-back for a processing BNPL/manual refund — settle it (posts the
    // deferred refund_payable ↔ escrow_held clearing). Idempotent.
    [HttpPost("{id}/[action]")]
    [ProducesOkApiResponseType<RefundSettlementResult>]
    public async Task<IActionResult> ConfirmSettlement(long id, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new ConfirmRefundSettlementCommand(id), cancellationToken));

    // Reconciliation reported the customer cash-back did not land — fail the processing refund (no ledger moves).
    [HttpPost("{id}/[action]")]
    [ProducesOkApiResponseType<RefundSettlementResult>]
    public async Task<IActionResult> MarkFailed(long id, MarkRefundFailedBody body, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new MarkRefundSettlementFailedCommand(id, body.Reason), cancellationToken));
}

/// <summary>The mark-failed body (the id comes from the route).</summary>
public record MarkRefundFailedBody(string? Reason);
