using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using ShiftScheduler.Services; using ShiftScheduler.Shared; namespace ShiftScheduler.Server.Controllers { [ApiController] [Route("api/[controller]")] [Authorize(Policy = "AllowedEmails")] public class ShiftController : ControllerBase { private readonly IcsExportService _icsService; private readonly PdfExportService _pdfExportService; private readonly ITransportService _transportService; private readonly IConfigurationService _configurationService; private readonly IGoogleCalendarService _googleCalendarService; public ShiftController( IcsExportService icsService, PdfExportService pdfExportService, ITransportService transportService, IConfigurationService configurationService, IGoogleCalendarService googleCalendarService) { _icsService = icsService; _pdfExportService = pdfExportService; _transportService = transportService; _configurationService = configurationService; _googleCalendarService = googleCalendarService; } [HttpGet("shifts")] public IActionResult GetShifts() { return Ok(_configurationService.GetShifts()); } [HttpPost("shift_transport")] public async Task GetShiftTransport([FromBody] ShiftTransportRequest request) { var shift = _configurationService.GetShifts().FirstOrDefault(s => s.Name == request.ShiftName); if (shift == null) { return NotFound($"Shift '{request.ShiftName}' not found"); } var transportConfig = _configurationService.GetTransportConfiguration(); TransportConnection? morningTransport = null; TransportConnection? afternoonTransport = null; var shifTimes = _configurationService.ParseShiftTimes(request.Date, shift); // Get transport for morning shift if it has morning time if (!string.IsNullOrEmpty(shift.MorningTime)) { if (shifTimes.MorningStart.HasValue) { morningTransport = await _transportService.GetConnectionAsync(shifTimes.MorningStart.Value); } } // Get transport for afternoon shift if it has afternoon time // But only if the break between morning and afternoon is long enough if (!string.IsNullOrEmpty(shift.AfternoonTime)) { var shouldLoadAfternoonTransport = true; // If both morning and afternoon shifts exist, check break duration if (!string.IsNullOrEmpty(shift.MorningTime) && !string.IsNullOrEmpty(shift.AfternoonTime)) { if (shifTimes.MorningEnd.HasValue && shifTimes.AfternoonStart.HasValue) { var breakDurationMinutes = (shifTimes.AfternoonStart.Value - shifTimes.MorningEnd.Value).TotalMinutes; shouldLoadAfternoonTransport = breakDurationMinutes >= transportConfig.MinBreakMinutes; } } if (shouldLoadAfternoonTransport) { if (shifTimes.AfternoonStart.HasValue) { afternoonTransport = await _transportService.GetConnectionAsync(shifTimes.AfternoonStart.Value); } } } var shiftWithTransport = new ShiftWithTransport { Date = request.Date, Shift = shift, MorningTransport = morningTransport, AfternoonTransport = afternoonTransport, }; return Ok(shiftWithTransport); } [HttpPost("export_ics")] public IActionResult ExportIcsWithTransport([FromBody] List shiftsWithTransport) { var ics = _icsService.GenerateIcs(shiftsWithTransport); return File(System.Text.Encoding.UTF8.GetBytes(ics), "text/calendar", "schedule.ics"); } [HttpPost("export_pdf")] public IActionResult ExportPdfWithTransport([FromBody] List shiftsWithTransport) { var pdf = _pdfExportService.GenerateMonthlySchedulePdf(shiftsWithTransport); return File(pdf, "application/pdf", "schedule.pdf"); } [HttpPost("save_schedule")] public async Task SaveSchedule([FromBody] SaveScheduleRequest request) { try { await _configurationService.SaveScheduleAsync(request.Year, request.Month, request.Schedule); return Ok(); } catch (Exception ex) { return StatusCode(500, $"Error saving schedule: {ex.Message}"); } } [HttpGet("load_schedule/{year}/{month}")] public async Task LoadSchedule(int year, int month) { try { var schedule = await _configurationService.LoadScheduleAsync(year, month); return Ok(schedule); } catch (Exception ex) { return StatusCode(500, $"Error loading schedule: {ex.Message}"); } } [HttpDelete("delete_schedule/{year}/{month}")] public async Task DeleteSchedule(int year, int month) { try { await _configurationService.DeleteScheduleAsync(year, month); return Ok(); } catch (Exception ex) { return StatusCode(500, $"Error deleting schedule: {ex.Message}"); } } [HttpGet("google_calendars")] public async Task GetGoogleCalendars() { try { var calendars = await _googleCalendarService.GetCalendarsAsync(); return Ok(calendars.Select(c => new { Id = c.Id, Summary = c.Summary })); } catch (Exception ex) { return StatusCode(500, $"Error retrieving calendars: {ex.Message}"); } } [HttpPost("sync_to_google_calendar")] public async Task SyncToGoogleCalendar([FromBody] SyncToGoogleCalendarRequest request) { try { await _googleCalendarService.SyncShiftsToCalendarAsync(request.CalendarId, request.ShiftsWithTransport); return Ok(new { message = "Shifts synced to Google Calendar successfully!" }); } catch (Exception ex) { return StatusCode(500, $"Error syncing to Google Calendar: {ex.Message}"); } } } public class ShiftTransportRequest { public string ShiftName { get; set; } = string.Empty; public DateTime Date { get; set; } } public class SaveScheduleRequest { public int Year { get; set; } public int Month { get; set; } public Dictionary Schedule { get; set; } = new(); } public class SyncToGoogleCalendarRequest { public string CalendarId { get; set; } = string.Empty; public List ShiftsWithTransport { get; set; } = []; } }