using System.ComponentModel.DataAnnotations;
using Asp.Versioning;
using Baya.Application.Features.Messaging.Commands.AddParticipant;
using Baya.Application.Features.Messaging.Commands.CloseTicket;
using Baya.Application.Features.Messaging.Commands.LogEmergencyTicket;
using Baya.Application.Features.Messaging.Commands.OpenTicket;
using Baya.Application.Features.Messaging.Commands.PostMessage;
using Baya.Application.Features.Messaging.Commands.RemoveParticipant;
using Baya.Application.Features.Messaging.Commands.ReopenTicket;
using Baya.Application.Features.Messaging.Queries.GetTicketThread;
using Baya.Application.Features.Messaging.Queries.ListMyTickets;
using Baya.Application.Models.Common;
using Baya.Application.Models.Messaging;
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 ticket system — the only sanctioned post-booking communication channel. All reads/writes are
/// participation-gated (staff may attach to any ticket). The user thread view never contains an internal note.
/// </summary>
[ApiVersion("1")]
[ApiController]
[Route("api/v{version:apiVersion}/tickets")]
[Authorize]
[Display(Description = "Post-booking ticket communication (participant-scoped)")]
public sealed class TicketsController(ISender sender) : BaseController
{
    [HttpPost]
    [ProducesOkApiResponseType<OpenTicketResult>]
    public async Task<IActionResult> Open(OpenTicketCommand command, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(command, cancellationToken));

    [HttpPost("emergency")]
    [ProducesOkApiResponseType<OpenTicketResult>]
    public async Task<IActionResult> Emergency(LogEmergencyTicketCommand command, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(command, cancellationToken));

    [HttpPost("{id}/messages")]
    [ProducesOkApiResponseType<PostMessageResult>]
    public async Task<IActionResult> PostMessage(long id, PostMessageCommand command, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(command with { TicketId = id }, cancellationToken));

    [HttpPost("{id}/participants")]
    [ProducesOkApiResponseType]
    public async Task<IActionResult> AddParticipant(long id, AddParticipantCommand command, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(command with { TicketId = id }, cancellationToken));

    [HttpDelete("{id}/participants/{userId}")]
    [ProducesOkApiResponseType]
    public async Task<IActionResult> RemoveParticipant(long id, int userId, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new RemoveParticipantCommand(id, userId), cancellationToken));

    [HttpPost("{id}/close")]
    [ProducesOkApiResponseType]
    public async Task<IActionResult> Close(long id, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new CloseTicketCommand(id), cancellationToken));

    [HttpPost("{id}/reopen")]
    [ProducesOkApiResponseType]
    public async Task<IActionResult> Reopen(long id, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new ReopenTicketCommand(id), cancellationToken));

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

    // User view — internal notes are stripped in the query projection.
    [HttpGet("{id}")]
    [ProducesOkApiResponseType<TicketThreadDto>]
    public async Task<IActionResult> Thread(long id, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new GetTicketThreadQuery(id, AsAdmin: false), cancellationToken));
}
