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); var validationError = WorkOrderOperationalWeek.ValidateWeekWindow(weekStart, weekEnd); if (validationError != null) throw new ArgumentException(validationError); var dataQuery = new WorkOrderBoardQuery( weekStart, weekEnd, query.Dispatchers, query.MyWorkOrders, query.Types, query.Overdue, 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 => MapRawRow(r, utcNow)).ToList(), Unscheduled = result.UnscheduledRows.Select(r => MapRawRow(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(); } public async Task GetBoardRowAsync(int workOrderId) { var raw = await _boardDataService.GetBoardRowByIdAsync(workOrderId); return raw == null ? null : MapRawRow(raw, DateTime.UtcNow); } public static WorkOrderBoardRowDto MapRawRow(WorkOrderBoardRawRow row, DateTime utcNow) { // Appt column: date prefers dispatch appointment (vendor slot), then WO ScheduledDate. // Time prefers WO ScheduledStart/End (dispatcher window), then dispatch datetime. 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, ServiceNotes = row.ServiceNotes, ExtraServices = ParseExtraServices(row.ExtraServices), DocStatus = row.DocStatus, FlagColor = row.FlagColor, PrimaryDispatchId = row.PrimaryDispatchId, RowVersion = row.RowVersion, DispatchRowVersion = row.DispatchRowVersion }; } private static string FormatName(string? firstName, string? lastName) => $"{firstName ?? ""} {lastName ?? ""}".Trim(); private static List? ParseExtraServices(string? json) { if (string.IsNullOrWhiteSpace(json)) return null; try { var list = System.Text.Json.JsonSerializer.Deserialize>(json); return list is { Count: > 0 } ? list : null; } catch (System.Text.Json.JsonException) { return null; } } } }