using Data.SeaHavenIndustries; using FluentValidation; using SeaHaven.DataServices.Dto; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.DTOs; using SeaHaven.Services.Interfaces; using SeaHaven.Services.Validation; namespace SeaHaven.Services.Implementation { /// /// Dispatch service implementation /// Contains business logic, validation, and orchestration for Dispatch operations /// public class DispatchService : IDispatchService { private readonly IDispatchDataService _dispatchDataService; private readonly ICreateDispatchValidation _createValidator; private readonly IUpdateDispatchValidation _updateValidator; public DispatchService( IDispatchDataService dispatchDataService, ICreateDispatchValidation createValidator, IUpdateDispatchValidation updateValidator) { _dispatchDataService = dispatchDataService; _createValidator = createValidator; _updateValidator = updateValidator; } public async Task GetDispatchByIdAsync(int id) { var dispatch = await _dispatchDataService.GetByIdAsync(id); return dispatch == null ? null : MapToDTO(dispatch); } public async Task GetDispatchByIdWithDetailsAsync(int id) { var dispatch = await _dispatchDataService.GetByIdWithDetailsAsync(id); return dispatch == null ? null : MapToDTO(dispatch); } public async Task> GetAllDispatchesAsync() { var dispatches = await _dispatchDataService.GetAllAsync(); return dispatches.Select(MapToDTO); } public async Task> GetDispatchesByVendorIdAsync(int vendorId) { var dispatches = await _dispatchDataService.GetByVendorIdAsync(vendorId); return dispatches.Select(MapToDTO); } public async Task> GetDispatchesPagedAsync(int page, int pageSize, string? search = null, string? status = null) { var (items, totalCount) = await _dispatchDataService.GetPagedAsync(page, pageSize, search, status); return new PagedResult { Items = items.Select(MapToDTO).ToList(), TotalCount = totalCount, Page = page, PageSize = pageSize }; } public async Task CreateDispatchAsync(CreateDispatchDTO dto, string userId) { var validationResult = await _createValidator.ValidateAsync(dto); if (!validationResult.IsValid) { throw new ValidationException(validationResult.Errors); } var dispatchNumber = await GenerateNextDispatchNumberAsync(); var dispatch = new Dispatch { VendorId = dto.VendorId, ScheduledDate = dto.ScheduledDate, Status = dto.Status ?? "Pending", DispatchNumber = dispatchNumber, CreatedDate = DateTime.UtcNow, createdby = userId }; var created = await _dispatchDataService.AddAsync(dispatch); return MapToDTO(created); } public async Task UpdateDispatchAsync(int id, UpdateDispatchDTO dto, string userId) { var validationResult = await _updateValidator.ValidateAsync(dto); if (!validationResult.IsValid) { throw new ValidationException(validationResult.Errors); } var dispatch = await _dispatchDataService.GetByIdAsync(id); if (dispatch == null) throw new InvalidOperationException($"Dispatch with ID {id} not found"); if (dto.VendorId.HasValue) dispatch.VendorId = dto.VendorId.Value; if (dto.ScheduledDate.HasValue) dispatch.ScheduledDate = dto.ScheduledDate; if (dto.CompletedDate.HasValue) dispatch.CompletedDate = dto.CompletedDate; if (dto.Status != null) dispatch.Status = dto.Status; dispatch.LastModificationTime = DateTime.UtcNow; if (int.TryParse(userId, out int userIdInt)) dispatch.LastModifierUserId = userIdInt; await _dispatchDataService.UpdateAsync(dispatch); return MapToDTO(dispatch); } public async Task DeleteDispatchAsync(int id, string userId) { var dispatch = await _dispatchDataService.GetByIdAsync(id); if (dispatch == null) throw new InvalidOperationException($"Dispatch with ID {id} not found"); dispatch.IsDeleted = true; dispatch.DeleterUserId = userId; dispatch.DeletionTime = DateTime.UtcNow; await _dispatchDataService.UpdateAsync(dispatch); } public async Task DispatchExistsAsync(int id) { return await _dispatchDataService.ExistsAsync(id); } public async Task GenerateNextDispatchNumberAsync() { var count = await _dispatchDataService.CountAsync(); return $"DISP-{(count + 1):D6}"; } public async Task GetTotalDispatchCountAsync() { return await _dispatchDataService.CountAsync(); } public async Task GetDispatchListAsync( string? search, string? status, int? vendorId, DateTime? dateFrom, DateTime? dateTo, string? sortBy, string? sortDir, int page, int pageSize, CancellationToken cancellationToken) { var query = new DispatchListQuery { Search = search, Status = status, VendorId = vendorId, DateFrom = dateFrom, DateTo = dateTo, SortBy = sortBy, SortDir = sortDir, Page = page, PageSize = pageSize }; var result = await _dispatchDataService.GetListAsync(query, cancellationToken); return new DispatchListResultDTO { Items = result.Items.Select(MapListEntry).ToList(), Total = result.Total, Page = result.Page, PageSize = result.PageSize }; } public async Task GetDispatchDetailAsync(int id, CancellationToken cancellationToken) { var detail = await _dispatchDataService.GetDetailAsync(id, cancellationToken); return detail == null ? null : MapDetail(detail); } private static DispatchListEntryDTO MapListEntry(DispatchListItemDTO d) { return new DispatchListEntryDTO { Id = d.Id, DispatchNumber = d.DispatchNumber, PONumber = d.PONumber, NTEAmount = d.NTEAmount, Status = d.Status, DispatchedAt = d.DispatchedAt, ScheduledDate = d.ScheduledDate, CompletedDate = d.CompletedDate, AcknowledgedAt = d.AcknowledgedAt, VerifiedAt = d.VerifiedAt, VendorId = d.VendorId, VendorName = d.VendorName, WorkOrderId = d.WorkOrderId, PrimaryWOInternalNumber = d.PrimaryWOInternalNumber, PrimaryWOTitle = d.PrimaryWOTitle, LocationName = d.LocationName, WorkOrderCount = d.WorkOrderCount, PendingUpliftCount = d.PendingUpliftCount }; } private static DispatchDetailResultDTO MapDetail(DispatchDetailDTO d) { return new DispatchDetailResultDTO { Id = d.Id, DispatchNumber = d.DispatchNumber, PONumber = d.PONumber, NTEAmount = d.NTEAmount, Description = d.Description, Status = d.Status, ScheduledDate = d.ScheduledDate, CompletedDate = d.CompletedDate, DispatchedAt = d.DispatchedAt, AcknowledgedAt = d.AcknowledgedAt, VerifiedAt = d.VerifiedAt, VerifiedBy = d.VerifiedBy, EmailSent = d.EmailSent, WorkOrderId = d.WorkOrderId, Vendor = d.Vendor == null ? null : new DispatchDetailVendorResultDTO { Id = d.Vendor.Id, CompanyName = d.Vendor.CompanyName, ContactName = d.Vendor.ContactName, Email = d.Vendor.Email, Phone = d.Vendor.Phone, Address = d.Vendor.Address, City = d.Vendor.City, State = d.Vendor.State, Zip = d.Vendor.Zip, TradeSpecialties = d.Vendor.TradeSpecialties }, PrimaryLocation = d.PrimaryLocation == null ? null : new DispatchDetailLocationResultDTO { Id = d.PrimaryLocation.Id, Name = d.PrimaryLocation.Name, Address1 = d.PrimaryLocation.Address1, City = d.PrimaryLocation.City, State = d.PrimaryLocation.State, Zip = d.PrimaryLocation.Zip }, WorkOrders = d.WorkOrders.Select(w => new DispatchDetailLinkedWorkOrderDTO { WorkOrderId = w.WorkOrderId, InternalWONumber = w.InternalWONumber, Title = w.Title, Priority = w.Priority, Status = w.Status, LocationName = w.LocationName, Trade = w.Trade, SubTrade = w.SubTrade, Problem = w.Problem }).ToList(), Checklist = d.Checklist.Select(c => new DispatchDetailChecklistDTO { Id = c.Id, ItemText = c.ItemText, IsCompleted = c.IsCompleted, CompletedBy = c.CompletedBy, CompletedAt = c.CompletedAt, SortOrder = c.SortOrder, WorkOrderId = c.WorkOrderId }).ToList(), Signoffs = d.Signoffs.Select(s => new DispatchDetailSignoffDTO { Id = s.Id, SignoffType = s.SignoffType, Name = s.Name, Signature = s.Signature, SignatureMethod = s.SignatureMethod, SignedAt = s.SignedAt }).ToList(), Comments = d.Comments.Select(c => new DispatchDetailCommentDTO { Id = c.Id, Commenttext = c.Commenttext, Commenter = c.Commenter, CommentType = c.CommentType, RecordType = c.RecordType, CreatedDate = c.CreatedDate, UserId = c.UserId, UserName = c.UserName }).ToList(), UpliftRequests = d.UpliftRequests.Select(u => new DispatchDetailUpliftDTO { Id = u.Id, CurrentNTE = u.CurrentNTE, RequestedNTE = u.RequestedNTE, Delta = u.Delta, VendorReason = u.VendorReason, Status = u.Status, RequiredTier = u.RequiredTier, RequestedByVendorName = u.RequestedByVendorName, RequestedAt = u.RequestedAt, DecidedAt = u.DecidedAt, DecisionNote = u.DecisionNote, DecidedByName = u.DecidedByName }).ToList(), AuditLog = d.AuditLog.Select(a => new DispatchDetailAuditLogDTO { Id = a.Id, Action = a.Action, FieldName = a.FieldName, OldValue = a.OldValue, NewValue = a.NewValue, CreatedAt = a.CreatedAt, UserId = a.UserId, UserName = a.UserName }).ToList() }; } private DispatchDTO MapToDTO(Dispatch dispatch) { return new DispatchDTO { Id = dispatch.Id, DispatchNumber = dispatch.DispatchNumber, Status = dispatch.Status, VendorId = dispatch.VendorId, VendorName = dispatch.Vendor?.CompanyName, ScheduledDate = dispatch.ScheduledDate, CompletedDate = dispatch.CompletedDate, CreatedDate = dispatch.CreatedDate, CreatedBy = dispatch.createdby }; } } }