// EN: Appointments Controller - Customer-facing appointment APIs.
// VI: Controller Appointments - APIs đặt lịch hẹn cho khách hàng.

using Asp.Versioning;
using BookingService.API.Application.Commands;
using BookingService.API.Application.DTOs;
using BookingService.API.Application.Queries;
using BookingService.API.Models.Requests;
using BookingService.API.Models.Responses;
using MediatR;
using Microsoft.AspNetCore.Mvc;

namespace BookingService.API.Controllers;

[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/appointments")]
[Produces("application/json")]
public class AppointmentsController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<AppointmentsController> _logger;

    public AppointmentsController(IMediator mediator, ILogger<AppointmentsController> logger)
    {
        _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    /// <summary>
    /// EN: Get  appointments by shop or customer with filtering.
    /// VI: Lấy danh sách cuộc hẹn theo shop hoặc customer với lọc.
    /// </summary>
    [HttpGet]
    [ProducesResponseType(typeof(ApiResponse<PaginatedList<AppointmentDto>>), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse<PaginatedList<AppointmentDto>>>> GetAppointments(
        [FromQuery] Guid? shopId,
        [FromQuery] Guid? customerId,
        [FromQuery] DateTime? startDate,
        [FromQuery] DateTime? endDate,
        [FromQuery] string? status,
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        CancellationToken cancellationToken = default)
    {
        PaginatedList<AppointmentDto> result;

        if (shopId.HasValue)
        {
            var query = new GetAppointmentsByShopQuery(shopId.Value, startDate, endDate, status, page, pageSize);
            result = await _mediator.Send(query, cancellationToken);
        }
        else if (customerId.HasValue)
        {
            var query = new GetAppointmentsByCustomerQuery(customerId.Value, page, pageSize);
            result = await _mediator.Send(query, cancellationToken);
        }
        else
        {
            return BadRequest(ApiResponse<PaginatedList<AppointmentDto>>.Fail("Either shopId or customerId must be provided"));
        }

        return Ok(ApiResponse<PaginatedList<AppointmentDto>>.Ok(result));
    }

    /// <summary>
    /// EN: Get appointment by ID.
    /// VI: Lấy chi tiết cuộc appointment theo ID.
    /// </summary>
    [HttpGet("{id:guid}")]
    [ProducesResponseType(typeof(ApiResponse<AppointmentDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<ApiResponse<AppointmentDto>>> GetAppointment(
        Guid id,
        CancellationToken cancellationToken = default)
    {
        var query = new GetAppointmentQuery(id);
        var result = await _mediator.Send(query, cancellationToken);

        if (result == null)
        {
            return NotFound(ApiResponse<AppointmentDto>.Fail($"Appointment {id} not found"));
        }

        return Ok(ApiResponse<AppointmentDto>.Ok(result));
    }

    /// <summary>
    /// EN: Create a new appointment.
    /// VI: Tạo cuộc hẹn mới.
    /// </summary>
    [HttpPost]
    [ProducesResponseType(typeof(ApiResponse<AppointmentDto>), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<ActionResult<ApiResponse<AppointmentDto>>> CreateAppointment(
        [FromBody] CreateAppointmentRequest request,
        CancellationToken cancellationToken = default)
    {
        var command = new CreateAppointmentCommand(
            request.ShopId,
            request.ServiceId,
            request.StartTime,
            request.EndTime,
            request.CustomerId,
            request.StaffId,
            request.ResourceId
        );

        var result = await _mediator.Send(command, cancellationToken);

        return CreatedAtAction(
            nameof(GetAppointment),
            new { id = result.Id },
            ApiResponse<AppointmentDto>.Ok(result, "Appointment created successfully"));
    }

    /// <summary>
    /// EN: Update appointment status.
    /// VI: Cập nhật trạng thái cuộc hẹn.
    /// </summary>
    [HttpPatch("{id:guid}/status")]
    [ProducesResponseType(typeof(ApiResponse<AppointmentDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<ApiResponse<AppointmentDto>>> UpdateStatus(
        Guid id,
        [FromBody] UpdateStatusRequest request,
        CancellationToken cancellationToken = default)
    {
        var command = new UpdateAppointmentStatusCommand(id, request.Action);
        var result = await _mediator.Send(command, cancellationToken);

        return Ok(ApiResponse<AppointmentDto>.Ok(result, "Status updated successfully"));
    }

    /// <summary>
    /// EN: Cancel an appointment.
    /// VI: Hủy cuộc hẹn.
    /// </summary>
    [HttpDelete("{id:guid}")]
    [ProducesResponseType(typeof(ApiResponse<bool>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<ApiResponse<bool>>> CancelAppointment(
        Guid id,
        [FromBody] CancelRequest request,
        CancellationToken cancellationToken = default)
    {
        var command = new CancelAppointmentCommand(id, request.Reason);
        var result = await _mediator.Send(command, cancellationToken);

        return Ok(ApiResponse<bool>.Ok(result, "Appointment cancelled successfully"));
    }
}
