using AutoMapper; using PowderCoating.Core.Entities; using PowderCoating.Core.Enums; using PowderCoating.Application.DTOs.Job; namespace PowderCoating.Application.Mappings; public class JobProfile : Profile { public JobProfile() { // Job to JobDto - Map all lookup properties from navigation CreateMap() .ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer != null ? (!string.IsNullOrWhiteSpace(src.Customer.CompanyName) ? src.Customer.CompanyName : $"{src.Customer.ContactFirstName} {src.Customer.ContactLastName}".Trim()) : string.Empty)) .ForMember(dest => dest.CustomerCompanyName, opt => opt.MapFrom(src => src.Customer != null ? src.Customer.CompanyName : null)) .ForMember(dest => dest.CustomerContactName, opt => opt.MapFrom(src => src.Customer != null ? $"{src.Customer.ContactFirstName} {src.Customer.ContactLastName}".Trim() : null)) .ForMember(dest => dest.AssignedWorkerName, opt => opt.MapFrom(src => src.AssignedUser != null ? src.AssignedUser.FullName : null)) // Status lookup mappings .ForMember(dest => dest.JobStatusId, opt => opt.MapFrom(src => src.JobStatusId)) .ForMember(dest => dest.StatusCode, opt => opt.MapFrom(src => src.JobStatus.StatusCode)) .ForMember(dest => dest.StatusDisplayName, opt => opt.MapFrom(src => src.JobStatus.DisplayName)) .ForMember(dest => dest.StatusColorClass, opt => opt.MapFrom(src => src.JobStatus.ColorClass)) .ForMember(dest => dest.StatusIconClass, opt => opt.MapFrom(src => src.JobStatus.IconClass)) .ForMember(dest => dest.StatusDisplayOrder, opt => opt.MapFrom(src => src.JobStatus.DisplayOrder)) .ForMember(dest => dest.StatusIsTerminal, opt => opt.MapFrom(src => src.JobStatus.IsTerminalStatus)) .ForMember(dest => dest.StatusIsWIP, opt => opt.MapFrom(src => src.JobStatus.IsWorkInProgressStatus)) // Priority lookup mappings .ForMember(dest => dest.JobPriorityId, opt => opt.MapFrom(src => src.JobPriorityId)) .ForMember(dest => dest.PriorityCode, opt => opt.MapFrom(src => src.JobPriority.PriorityCode)) .ForMember(dest => dest.PriorityDisplayName, opt => opt.MapFrom(src => src.JobPriority.DisplayName)) .ForMember(dest => dest.PriorityColorClass, opt => opt.MapFrom(src => src.JobPriority.ColorClass)) .ForMember(dest => dest.PriorityIconClass, opt => opt.MapFrom(src => src.JobPriority.IconClass)) .ForMember(dest => dest.PriorityDisplayOrder, opt => opt.MapFrom(src => src.JobPriority.DisplayOrder)) // Oven selection .ForMember(dest => dest.OvenLabel, opt => opt.MapFrom(src => src.OvenCost != null ? src.OvenCost.Label : null)) .ForMember(dest => dest.Items, opt => opt.MapFrom(src => src.JobItems)) // Prep services mappings .ForMember(dest => dest.PrepServices, opt => opt.MapFrom(src => src.JobPrepServices.Select(jps => jps.PrepService).ToList())) .ForMember(dest => dest.PrepServiceIds, opt => opt.MapFrom(src => src.JobPrepServices.Select(jps => jps.PrepServiceId).ToList())) .ForMember(dest => dest.TimeEntries, opt => opt.MapFrom(src => src.TimeEntries)) .ForMember(dest => dest.IsReworkJob, opt => opt.MapFrom(src => src.IsReworkJob)) .ForMember(dest => dest.OriginalJobId, opt => opt.MapFrom(src => src.OriginalJobId)) .ForMember(dest => dest.OriginalJobNumber, opt => opt.MapFrom(src => src.OriginalJob != null ? src.OriginalJob.JobNumber : null)) .ForMember(dest => dest.IntakeCheckedByName, opt => opt.MapFrom(src => src.IntakeCheckedBy != null ? src.IntakeCheckedBy.FullName : null)) .ForMember(dest => dest.CustomerNotifyBySms, opt => opt.MapFrom(src => src.Customer != null && src.Customer.NotifyBySms)) .ForMember(dest => dest.CustomerMobilePhone, opt => opt.MapFrom(src => src.Customer != null ? (src.Customer.MobilePhone ?? src.Customer.Phone) : null)); // JobTimeEntry → JobTimeEntryDto CreateMap() .ForMember(dest => dest.WorkerName, opt => opt.MapFrom(src => src.Worker != null ? src.Worker.Name : string.Empty)) .ForMember(dest => dest.WorkerRole, opt => opt.MapFrom(src => src.Worker != null ? FormatEnumName(src.Worker.Role.ToString()) : string.Empty)); // CreateJobDto to Job CreateMap() .ForMember(dest => dest.JobNumber, opt => opt.Ignore()) // Generated by system .ForMember(dest => dest.JobStatus, opt => opt.Ignore()) // Will be set by FK .ForMember(dest => dest.JobPriority, opt => opt.Ignore()) // Will be set by FK .ForMember(dest => dest.OvenCost, opt => opt.Ignore()) // Will be set by FK .ForMember(dest => dest.JobPrepServices, opt => opt.Ignore()) // Handled separately .ForMember(dest => dest.JobItems, opt => opt.Ignore()); // Handled separately // UpdateJobDto to Job CreateMap() .ForMember(dest => dest.JobNumber, opt => opt.Ignore()) // Cannot be changed .ForMember(dest => dest.JobStatus, opt => opt.Ignore()) // Will be set by FK .ForMember(dest => dest.JobPriority, opt => opt.Ignore()) // Will be set by FK .ForMember(dest => dest.OvenCost, opt => opt.Ignore()) // Will be set by FK .ForMember(dest => dest.JobPrepServices, opt => opt.Ignore()) // Handled separately .ForMember(dest => dest.JobItems, opt => opt.Ignore()); // Handled separately // Job to UpdateJobDto (needed for Edit GET action) CreateMap() .ForMember(dest => dest.JobStatusId, opt => opt.MapFrom(src => src.JobStatusId)) .ForMember(dest => dest.JobPriorityId, opt => opt.MapFrom(src => src.JobPriorityId)) .ForMember(dest => dest.PrepServiceIds, opt => opt.MapFrom(src => src.JobPrepServices.Select(jps => jps.PrepServiceId).ToList())); // Job to JobListDto CreateMap() .ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer != null ? (!string.IsNullOrWhiteSpace(src.Customer.CompanyName) ? src.Customer.CompanyName : $"{src.Customer.ContactFirstName} {src.Customer.ContactLastName}".Trim()) : string.Empty)) .ForMember(dest => dest.AssignedWorkerName, opt => opt.MapFrom(src => src.AssignedUser != null ? src.AssignedUser.FullName : null)) // Status lookup mappings .ForMember(dest => dest.JobStatusId, opt => opt.MapFrom(src => src.JobStatusId)) .ForMember(dest => dest.StatusCode, opt => opt.MapFrom(src => src.JobStatus.StatusCode)) .ForMember(dest => dest.StatusDisplayName, opt => opt.MapFrom(src => src.JobStatus.DisplayName)) .ForMember(dest => dest.StatusColorClass, opt => opt.MapFrom(src => src.JobStatus.ColorClass)) .ForMember(dest => dest.StatusIsWIP, opt => opt.MapFrom(src => src.JobStatus.IsWorkInProgressStatus)) // Priority lookup mappings .ForMember(dest => dest.JobPriorityId, opt => opt.MapFrom(src => src.JobPriorityId)) .ForMember(dest => dest.PriorityCode, opt => opt.MapFrom(src => src.JobPriority.PriorityCode)) .ForMember(dest => dest.PriorityDisplayName, opt => opt.MapFrom(src => src.JobPriority.DisplayName)) .ForMember(dest => dest.PriorityColorClass, opt => opt.MapFrom(src => src.JobPriority.ColorClass)) .ForMember(dest => dest.CustomerNotifyByEmail, opt => opt.MapFrom(src => src.Customer == null || src.Customer.NotifyByEmail)); // JobItem mappings CreateMap() .ForMember(dest => dest.Coats, opt => opt.MapFrom(src => src.Coats)) .ForMember(dest => dest.PrepServices, opt => opt.MapFrom(src => src.PrepServices)); CreateMap() .ForMember(dest => dest.PrepServiceName, opt => opt.MapFrom(src => src.PrepService != null ? src.PrepService.ServiceName : null)); CreateMap() .ForMember(dest => dest.TotalPrice, opt => opt.MapFrom(src => src.UnitPrice * src.Quantity)); CreateMap(); CreateMap(); // JobItemCoat mappings CreateMap() .ForMember(dest => dest.VendorName, opt => opt.MapFrom(src => src.Vendor != null ? src.Vendor.CompanyName : null)); // Job to ShopFloorJobDto CreateMap() .ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer != null ? (!string.IsNullOrWhiteSpace(src.Customer.CompanyName) ? src.Customer.CompanyName : $"{src.Customer.ContactFirstName} {src.Customer.ContactLastName}".Trim()) : string.Empty)) .ForMember(dest => dest.AssignedWorkerName, opt => opt.MapFrom(src => src.AssignedUser != null ? src.AssignedUser.FullName : null)) // Status lookup mappings .ForMember(dest => dest.JobStatusId, opt => opt.MapFrom(src => src.JobStatusId)) .ForMember(dest => dest.StatusCode, opt => opt.MapFrom(src => src.JobStatus.StatusCode)) .ForMember(dest => dest.StatusDisplayName, opt => opt.MapFrom(src => src.JobStatus.DisplayName)) .ForMember(dest => dest.StatusColorClass, opt => opt.MapFrom(src => src.JobStatus.ColorClass)) // Priority lookup mappings .ForMember(dest => dest.JobPriorityId, opt => opt.MapFrom(src => src.JobPriorityId)) .ForMember(dest => dest.PriorityCode, opt => opt.MapFrom(src => src.JobPriority.PriorityCode)) .ForMember(dest => dest.PriorityDisplayName, opt => opt.MapFrom(src => src.JobPriority.DisplayName)) .ForMember(dest => dest.PriorityColorClass, opt => opt.MapFrom(src => src.JobPriority.ColorClass)) .ForMember(dest => dest.ItemCount, opt => opt.MapFrom(src => src.JobItems.Count)); // Note: NextSteps will be removed - was workflow logic that will be reimplemented later // JobPhoto mappings CreateMap() .ForMember(dest => dest.PhotoTypeDisplay, opt => opt.MapFrom(src => FormatEnumName(src.PhotoType.ToString()))) .ForMember(dest => dest.UploadedByName, opt => opt.MapFrom(src => src.UploadedBy != null ? src.UploadedBy.FullName : "Unknown")); CreateMap(); CreateMap(); // ReworkRecord → ReworkRecordDto CreateMap() .ForMember(dest => dest.ReworkTypeDisplay, opt => opt.MapFrom(src => FormatEnumName(src.ReworkType.ToString()))) .ForMember(dest => dest.ReasonDisplay, opt => opt.MapFrom(src => FormatReworkReason(src.Reason))) .ForMember(dest => dest.DiscoveredByDisplay, opt => opt.MapFrom(src => src.DiscoveredBy == ReworkDiscoveredBy.Internal ? "Internal (QC)" : "Customer")) .ForMember(dest => dest.StatusDisplay, opt => opt.MapFrom(src => FormatEnumName(src.Status.ToString()))) .ForMember(dest => dest.StatusColorClass, opt => opt.MapFrom(src => GetReworkStatusColor(src.Status))) .ForMember(dest => dest.ResolutionDisplay, opt => opt.MapFrom(src => src.Resolution.HasValue ? FormatReworkResolution(src.Resolution.Value) : null)) .ForMember(dest => dest.JobItemDescription, opt => opt.MapFrom(src => src.JobItem != null ? src.JobItem.Description : null)) .ForMember(dest => dest.ReworkJobNumber, opt => opt.MapFrom(src => src.ReworkJob != null ? src.ReworkJob.JobNumber : null)); // Job → JobDto (rework fields) // (IsReworkJob and OriginalJobId map by convention; OriginalJobNumber needs explicit map — handled in controller) // Job → JobListDto (rework fields map by convention) // JobChangeHistory -> JobChangeHistoryDto CreateMap() .ForMember(dest => dest.ChangedByName, opt => opt.MapFrom(src => src.ChangedBy != null ? $"{src.ChangedBy.FirstName} {src.ChangedBy.LastName}" : "Unknown")); } private static string FormatEnumName(string enumName) => System.Text.RegularExpressions.Regex.Replace(enumName, "([a-z])([A-Z])", "$1 $2"); private static string FormatReworkReason(ReworkReason reason) => reason switch { ReworkReason.AdhesionFailure => "Adhesion Failure", ReworkReason.Contamination => "Contamination", ReworkReason.ColorMismatch => "Color Mismatch", ReworkReason.RunsSags => "Runs / Sags", ReworkReason.SurfacePrepFailure => "Surface Prep Failure", ReworkReason.OvenIssue => "Oven Issue", ReworkReason.InsufficientCoverage => "Insufficient Coverage", ReworkReason.HandlingDamage => "Handling Damage", _ => "Other" }; private static string FormatReworkResolution(ReworkResolution resolution) => resolution switch { ReworkResolution.RecoatedNoCharge => "Recoated — No Charge", ReworkResolution.RecoatedBilled => "Recoated — Billed to Customer", ReworkResolution.CustomerCredited => "Customer Credited", ReworkResolution.WrittenOff => "Written Off", ReworkResolution.NoActionRequired => "No Action Required", _ => resolution.ToString() }; private static string GetReworkStatusColor(ReworkStatus status) => status switch { ReworkStatus.Open => "danger", ReworkStatus.InProgress => "warning", ReworkStatus.Resolved => "success", ReworkStatus.WrittenOff => "secondary", ReworkStatus.Disputed => "info", _ => "secondary" }; }