// EN: Schedules Controller - Shop-wide staff schedule queries. // VI: Controller Schedules - Truy vấn lịch làm việc nhân viên theo shop. using Asp.Versioning; using BookingService.API.Application.DTOs; using BookingService.API.Application.Queries; using BookingService.API.Models.Responses; using BookingService.Domain.AggregatesModel.StaffAggregate; using BookingService.Infrastructure.Repositories; using MediatR; using Microsoft.AspNetCore.Mvc; namespace BookingService.API.Controllers; [ApiController] [ApiVersion("1.0")] [Route("api/v{version:apiVersion}/schedules")] [Produces("application/json")] public class SchedulesController : ControllerBase { private readonly IMediator _mediator; private readonly IStaffScheduleRepository _scheduleRepository; private readonly ILogger _logger; public SchedulesController(IMediator mediator, IStaffScheduleRepository scheduleRepository, ILogger logger) { _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); _scheduleRepository = scheduleRepository ?? throw new ArgumentNullException(nameof(scheduleRepository)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } /// /// EN: Get all staff schedules for a shop. /// VI: Lấy tất cả lịch làm việc nhân viên cho một shop. /// [HttpGet] [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task>>> GetSchedulesByShop( [FromQuery] Guid shopId, CancellationToken cancellationToken = default) { if (shopId == Guid.Empty) return BadRequest(ApiResponse>.Fail("Shop ID is required")); var query = new GetSchedulesByShopQuery(shopId); var result = await _mediator.Send(query, cancellationToken); return Ok(ApiResponse>.Ok(result)); } /// /// EN: Create a single schedule entry. /// VI: Tạo một entry lịch làm việc. /// [HttpPost] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task>> CreateSchedule( [FromBody] CreateScheduleRequest request, CancellationToken cancellationToken = default) { if (request.ShopId == Guid.Empty || request.StaffId == Guid.Empty) return BadRequest(ApiResponse.Fail("ShopId and StaffId are required")); if (!TimeOnly.TryParse(request.StartTime, out var startTime) || !TimeOnly.TryParse(request.EndTime, out var endTime)) return BadRequest(ApiResponse.Fail("Invalid time format. Use HH:mm")); var schedule = new StaffSchedule(request.StaffId, request.ShopId, request.DayOfWeek, startTime, endTime); _scheduleRepository.Add(schedule); await _scheduleRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); _logger.LogInformation("Schedule created: {Id} for staff {StaffId}", schedule.Id, request.StaffId); var dto = new StaffScheduleDto { Id = schedule.Id, StaffId = schedule.StaffId, ShopId = schedule.ShopId, DayOfWeek = schedule.DayOfWeek, StartTime = schedule.StartTime, EndTime = schedule.EndTime }; return Created($"/api/v1/schedules/{schedule.Id}", ApiResponse.Ok(dto)); } /// /// EN: Delete a schedule entry by ID. /// VI: Xóa một entry lịch làm việc theo ID. /// [HttpDelete("{id:guid}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteSchedule(Guid id, CancellationToken cancellationToken = default) { var schedule = await _scheduleRepository.GetByIdAsync(id, cancellationToken); if (schedule == null) return NotFound(ApiResponse.Fail("Schedule not found")); _scheduleRepository.Remove(schedule); await _scheduleRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); _logger.LogInformation("Schedule deleted: {Id}", id); return Ok(new { success = true, message = "Schedule deleted" }); } } public record CreateScheduleRequest { public Guid ShopId { get; init; } public Guid StaffId { get; init; } public int DayOfWeek { get; init; } public string StartTime { get; init; } = "08:00"; public string EndTime { get; init; } = "17:00"; }