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<IActionResult> 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<QueueBoardDto>(true, board));
    }

    [HttpPost("next")]
    public async Task<IActionResult> 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<object>(false, null, new ApiError(error, "Branch not found.")));
        if (error == "ORDER_NOT_FOUND")
            return NotFound(new ApiResponse<object>(false, null, new ApiError(error, "Order not found.")));
        return Ok(new ApiResponse<QueueTicketDto>(true, ticket));
    }

    [HttpPatch("{ticketId}/status")]
    public async Task<IActionResult> 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<object>(false, null, new ApiError(error, "Ticket not found.")));
        if (error == "TICKET_EXPIRED")
            return BadRequest(new ApiResponse<object>(false, null,
                new ApiError(error, "Ticket is from a previous day.")));
        return Ok(new ApiResponse<QueueTicketDto>(true, ticket));
    }

    [HttpPost("call-next")]
    public async Task<IActionResult> 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<QueueBoardDto>(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<QueueBoardDto>(true, updated));
    }
}
