using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using WorkClub.Api.Services; using WorkClub.Application.Shifts.DTOs; namespace WorkClub.Api.Endpoints.Shifts; public static class ShiftEndpoints { public static void MapShiftEndpoints(this IEndpointRouteBuilder app) { var group = app.MapGroup("/api/shifts"); group.MapGet("", GetShifts) .RequireAuthorization("RequireMember") .WithName("GetShifts"); group.MapGet("{id:guid}", GetShift) .RequireAuthorization("RequireMember") .WithName("GetShift"); group.MapPost("", CreateShift) .RequireAuthorization("RequireManager") .WithName("CreateShift"); group.MapPut("{id:guid}", UpdateShift) .RequireAuthorization("RequireManager") .WithName("UpdateShift"); group.MapDelete("{id:guid}", DeleteShift) .RequireAuthorization("RequireAdmin") .WithName("DeleteShift"); group.MapPost("{id:guid}/signup", SignUpForShift) .RequireAuthorization("RequireMember") .WithName("SignUpForShift"); group.MapDelete("{id:guid}/signup", CancelSignup) .RequireAuthorization("RequireMember") .WithName("CancelSignup"); } private static async Task> GetShifts( ShiftService shiftService, [FromQuery] DateTimeOffset? from = null, [FromQuery] DateTimeOffset? to = null, [FromQuery] int page = 1, [FromQuery] int pageSize = 20) { var result = await shiftService.GetShiftsAsync(from, to, page, pageSize); return TypedResults.Ok(result); } private static async Task, NotFound>> GetShift( Guid id, ShiftService shiftService) { var result = await shiftService.GetShiftByIdAsync(id); if (result == null) return TypedResults.NotFound(); return TypedResults.Ok(result); } private static async Task, BadRequest>> CreateShift( CreateShiftRequest request, ShiftService shiftService, HttpContext httpContext) { var userIdClaim = httpContext.User.FindFirst("sub")?.Value; if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var createdById)) { return TypedResults.BadRequest("Invalid user ID"); } var (shift, error) = await shiftService.CreateShiftAsync(request, createdById); if (error != null || shift == null) return TypedResults.BadRequest(error ?? "Failed to create shift"); return TypedResults.Created($"/api/shifts/{shift.Id}", shift); } private static async Task, NotFound, Conflict>> UpdateShift( Guid id, UpdateShiftRequest request, ShiftService shiftService) { var (shift, error, isConflict) = await shiftService.UpdateShiftAsync(id, request); if (error != null) { if (error == "Shift not found") return TypedResults.NotFound(); if (isConflict) return TypedResults.Conflict(error); } return TypedResults.Ok(shift!); } private static async Task> DeleteShift( Guid id, ShiftService shiftService) { var deleted = await shiftService.DeleteShiftAsync(id); if (!deleted) return TypedResults.NotFound(); return TypedResults.NoContent(); } private static async Task, Conflict>> SignUpForShift( Guid id, ShiftService shiftService, HttpContext httpContext) { var externalUserId = httpContext.User.FindFirst("sub")?.Value; if (string.IsNullOrEmpty(externalUserId)) { return TypedResults.UnprocessableEntity("Invalid user ID"); } var (success, error, isConflict) = await shiftService.SignUpForShiftAsync(id, externalUserId); if (!success) { if (error == "Shift not found" || error == "Member not found") return TypedResults.NotFound(); if (error == "Cannot sign up for past shifts") return TypedResults.UnprocessableEntity(error); if (isConflict) return TypedResults.Conflict(error!); } return TypedResults.Ok(); } private static async Task>> CancelSignup( Guid id, ShiftService shiftService, HttpContext httpContext) { var externalUserId = httpContext.User.FindFirst("sub")?.Value; if (string.IsNullOrEmpty(externalUserId)) { return TypedResults.UnprocessableEntity("Invalid user ID"); } var (success, error) = await shiftService.CancelSignupAsync(id, externalUserId); if (!success) { if (error == "Sign-up not found" || error == "Member not found") return TypedResults.NotFound(); return TypedResults.UnprocessableEntity(error!); } return TypedResults.Ok(); } }