using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Text;
using Asp.Versioning;
using Baya.Application.Features.Payments.Commands.HandlePaymentWebhook;
using Baya.Application.Models.Payments;
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 inbound PSP/BNPL callback surface. Authenticated by <b>signature</b>, not a user session, so it is
/// anonymous to the auth pipeline; at-least-once tolerant and idempotency-deduplicated on
/// <c>(provider, external_event_id)</c> before any money moves. The raw body is read verbatim and stored in
/// <c>payload_json</c>.
/// </summary>
[ApiVersion("1")]
[ApiController]
[Route("api/v{version:apiVersion}/webhooks")]
[AllowAnonymous]
[EnableRateLimiting(RateLimitingServiceExtension.WebhookPolicy)]
[Display(Description = "PSP/BNPL payment callbacks (signature-authenticated, idempotent)")]
public sealed class WebhooksController(ISender sender) : BaseController
{
    [HttpPost("payments/{provider}")]
    [ProducesOkApiResponseType<WebhookIngestResult>]
    public async Task<IActionResult> Payments(string provider, CancellationToken cancellationToken)
    {
        using var reader = new StreamReader(Request.Body, Encoding.UTF8, leaveOpen: true);
        var rawBody = await reader.ReadToEndAsync(cancellationToken);

        var headers = Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString(), StringComparer.OrdinalIgnoreCase);

        return OperationResult(await sender.Send(new HandlePaymentWebhookCommand(provider, headers, rawBody), cancellationToken));
    }
}
