using Data.SeaHavenIndustries.Enums; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.DTOs; using SeaHaven.Services.Helpers; using SeaHaven.Services.Interfaces; namespace SeaHaven.Services.Implementation { public class WorkOrderBoardService : IWorkOrderBoardService { private readonly IWorkOrderBoardDataService _boardDataService; public WorkOrderBoardService(IWorkOrderBoardDataService boardDataService) { _boardDataService = boardDataService; } public async Task GetBoardAsync( WorkOrderBoardQueryDto query, string? currentUserId) { var weekStart = query.WeekStart; var weekEnd = query.WeekEnd ?? weekStart.AddDays(4); ValidateWeekWindow(weekStart, weekEnd); var dataQuery = new WorkOrderBoardQuery( weekStart, weekEnd, query.Dispatchers, query.MyWorkOrders, query.Types, query.Search, currentUserId); var result = await _boardDataService.GetBoardRowsAsync(dataQuery); var utcNow = DateTime.UtcNow; return new WorkOrderBoardResponseDto { WeekStart = weekStart, WeekEnd = weekEnd, Counts = new WorkOrderBoardCountsDto { Total = result.ScheduledTotalBeforeSearch, Returned = result.ScheduledRows.Count }, Scheduled = result.ScheduledRows.Select(r => MapRow(r, utcNow)).ToList(), Unscheduled = result.UnscheduledRows.Select(r => MapRow(r, utcNow)).ToList() }; } public async Task> GetDispatcherLookupsAsync() { var rows = await _boardDataService.GetDispatcherLookupsAsync(); return rows.Select(r => new DispatcherLookupDto { Id = r.Id, Name = FormatName(r.FirstName, r.LastName), Initials = r.Initials, Color = r.Color }).ToList(); } private static void ValidateWeekWindow(DateOnly weekStart, DateOnly weekEnd) { if (weekEnd < weekStart) throw new ArgumentException("weekEnd must be on or after weekStart."); var spanDays = weekEnd.DayNumber - weekStart.DayNumber; if (spanDays > 6) throw new ArgumentException("Week window cannot exceed 7 days."); } private static WorkOrderBoardRowDto MapRow(WorkOrderBoardRawRow row, DateTime utcNow) { var apptStart = row.ScheduledStart ?? row.DispatchApptDate; var apptEnd = row.ScheduledEnd; return new WorkOrderBoardRowDto { Id = row.Id, WoNumber = row.InternalWONumber, RescheduleCount = row.RescheduleCount, CarriedOver = row.CarriedOver, WorkOrderType = row.WorkOrderType, IsPastDue = WorkOrderDerivedFields.IsPastDue(row.ScheduledDate, row.LifecycleStatus, utcNow), SiteCode = row.SiteCode, LocationName = row.LocationName, PocName = row.PocName, PocPhone = row.PocPhone, PocNotes = row.PocNotes, LifecycleStatus = row.LifecycleStatus, LifecycleStatusLabel = WorkOrderDerivedFields.GetLifecycleStatusLabel(row.LifecycleStatus), LegacyStatus = row.LegacyStatus, DispatcherId = row.AssignTo, DispatcherName = FormatName(row.DispatcherFirstName, row.DispatcherLastName), Initials = row.Initials, Color = row.Color, DueDate = row.DueDate, ScheduledDate = row.ScheduledDate, TargetWeek = row.TargetWeek, ScheduleWeekOnly = row.ScheduleWeekOnly, DayGroup = WorkOrderDerivedFields.GetDayGroup(row.ScheduledDate), VendorId = row.VendorId, VendorName = row.VendorName, TechName = row.TechName, TechPhone = row.TechPhone, ApptDate = row.DispatchApptDate ?? row.ScheduledDate, ApptTime = WorkOrderDerivedFields.FormatApptTime(apptStart, apptEnd), Pm = row.Trade ?? row.Problem, DocStatus = row.DocStatus, RowVersion = row.RowVersion }; } private static string FormatName(string? firstName, string? lastName) => $"{firstName ?? ""} {lastName ?? ""}".Trim(); } }