using Microsoft.AspNetCore.Mvc; using Meezi.API.Models.Queue; using Meezi.API.Services; using Meezi.Core.Enums; using Meezi.Core.Interfaces; using Meezi.Shared; namespace Meezi.API.Controllers; [Route("api/cafes/{cafeId}/queue")] public class QueueController : CafeApiControllerBase { private readonly IQueueService _queue; public QueueController(IQueueService queue) { _queue = queue; } [HttpGet("today")] public async Task GetToday( string cafeId, ITenantContext tenant, [FromQuery] string? branchId = null, CancellationToken ct = default) { if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied; var board = await _queue.GetTodayBoardAsync(cafeId, branchId, ct); return Ok(new ApiResponse(true, board)); } [HttpPost("next")] public async Task IssueNext( string cafeId, [FromBody] IssueQueueTicketRequest request, ITenantContext tenant, CancellationToken ct = default) { if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied; var (ticket, error) = await _queue.IssueNextAsync(cafeId, tenant.UserId, request, ct); if (error == "BRANCH_NOT_FOUND") return NotFound(new ApiResponse(false, null, new ApiError(error, "Branch not found."))); if (error == "ORDER_NOT_FOUND") return NotFound(new ApiResponse(false, null, new ApiError(error, "Order not found."))); return Ok(new ApiResponse(true, ticket)); } [HttpPatch("{ticketId}/status")] public async Task UpdateStatus( string cafeId, string ticketId, [FromBody] UpdateQueueTicketStatusRequest request, ITenantContext tenant, CancellationToken ct = default) { if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied; var (ticket, error) = await _queue.UpdateStatusAsync(cafeId, ticketId, request.Status, ct); if (error == "NOT_FOUND") return NotFound(new ApiResponse(false, null, new ApiError(error, "Ticket not found."))); if (error == "TICKET_EXPIRED") return BadRequest(new ApiResponse(false, null, new ApiError(error, "Ticket is from a previous day."))); return Ok(new ApiResponse(true, ticket)); } [HttpPost("call-next")] public async Task CallNext( string cafeId, ITenantContext tenant, [FromQuery] string? branchId = null, CancellationToken ct = default) { if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied; var board = await _queue.GetTodayBoardAsync(cafeId, branchId, ct); var next = board.Tickets.FirstOrDefault(t => t.Status == QueueTicketStatus.Waiting); if (next is null) return Ok(new ApiResponse(true, board)); foreach (var called in board.Tickets.Where(t => t.Status == QueueTicketStatus.Called)) { await _queue.UpdateStatusAsync(cafeId, called.Id, QueueTicketStatus.Done, ct); } await _queue.UpdateStatusAsync(cafeId, next.Id, QueueTicketStatus.Called, ct); var updated = await _queue.GetTodayBoardAsync(cafeId, branchId, ct); return Ok(new ApiResponse(true, updated)); } }