using System.ComponentModel.DataAnnotations;
using Asp.Versioning;
using Baya.Application.Features.Reviews.Commands.SubmitReview;
using Baya.Application.Features.Reviews.Queries.GetMyReview;
using Baya.Application.Features.Reviews.Queries.GetReviewEligibility;
using Baya.Application.Models.Reviews;
using Baya.WebFramework.Attributes;
using Baya.WebFramework.BaseController;
using Mediator;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Baya.Web.Api.Controllers.V1;

/// <summary>
/// The customer submits the one allowed review for a completed booking. Ownership, the completed/closed
/// eligibility gate, and the 1:1 rule are enforced in the handler; the booking id comes from the route.
/// </summary>
[ApiVersion("1")]
[ApiController]
[Route("api/v{version:apiVersion}/bookings")]
[Authorize]
[Display(Description = "Submit the one review for a completed booking (customer)")]
public sealed class BookingReviewsController(ISender sender) : BaseController
{
    [HttpPost("{bookingId}/review")]
    [ProducesOkApiResponseType<SubmitReviewResult>]
    public async Task<IActionResult> Review(long bookingId, SubmitReviewBody body, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(
            new SubmitReviewCommand(bookingId, body.Rating, body.Body, body.TagCodes), cancellationToken));

    // Can the caller review this booking? (completed/closed AND not already reviewed) — REQ-026.
    [HttpGet("{bookingId}/review_eligibility")]
    [ProducesOkApiResponseType<ReviewEligibilityDto>]
    public async Task<IActionResult> ReviewEligibility(long bookingId, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new GetReviewEligibilityQuery(bookingId), cancellationToken));

    // The caller's own review for the booking (persistent "under review" state across sessions) — REQ-026.
    [HttpGet("{bookingId}/my_review")]
    [ProducesOkApiResponseType<MyReviewDto>]
    public async Task<IActionResult> MyReview(long bookingId, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new GetMyReviewQuery(bookingId), cancellationToken));

    /// <summary>The review body (the booking id comes from the route).</summary>
    public record SubmitReviewBody(int Rating, string? Body, IReadOnlyList<string>? TagCodes);
}
