using System.Globalization; using System.Text.Json; using Data.SeaHavenIndustries; using SeaHaven.DataServices.Helpers; using SeaHaven.Services.DTOs; namespace SeaHaven.Services.Helpers { public static class WorkOrderCompletionSnapshotMapper { private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web); public static void Capture(WorkOrder workOrder) { var location = workOrder.Locations; var contact = workOrder.WorkOrderContacts? .OrderBy(item => item.Id) .FirstOrDefault(); // SH-379/SH-190: a work order without an override or link freezes the // Site's live primary contact, matching the board display precedence. var sitePrimary = WorkOrderPocSiteContact.ResolvePrimary(location?.Contacts); var pocName = FirstNotBlank( workOrder.PocName, JoinName(contact?.POC?.FirstName, contact?.POC?.MiddleName, contact?.POC?.LastName), WorkOrderPocSiteContact.DisplayName(sitePrimary)); var pocPhone = FirstNotBlank(workOrder.PocPhone, contact?.POC?.PhoneNumber, sitePrimary?.PhoneNumber); var pocNotes = FirstNotBlank(workOrder.PocNotes, contact?.Notes, location?.Notes); var contacts = new List(); AddContact(contacts, pocName, pocPhone); foreach (var additional in WorkOrderAdditionalContactsMapper.ParseJson(workOrder.AdditionalContacts) ?? Enumerable.Empty()) { AddContact(contacts, additional.Name, additional.Phone); } workOrder.FrozenSite = JsonSerializer.Serialize( new WorkOrderFrozenSite { Code = workOrder.SiteCode, Label = FirstNotBlank(location?.Name, location?.Title, workOrder.SiteCode), Address = JoinAddress(location?.Address1, location?.Address2), City = location?.City, State = location?.State, Zip = location?.Zip, Phone = location?.PhoneNumber, Email = location?.Email, Maps = location == null ? null : BuildMapsUrl(location) }, JsonOptions); var liveVendor = ResolveLiveVendor(workOrder.PrimaryDispatch); workOrder.FrozenCompany = liveVendor == null ? null : JsonSerializer.Serialize( new WorkOrderFrozenCompany { Name = liveVendor.CompanyName, ContactName = workOrder.TechnicianAssigned == false ? null : liveVendor.ContactName, TechnicianAssigned = workOrder.TechnicianAssigned, Address = liveVendor.Address, City = liveVendor.City, State = liveVendor.State, Zip = liveVendor.Zip, Phone = FirstNotBlank(liveVendor.CompanyPhone, liveVendor.Phone), Email = liveVendor.Email, Maps = liveVendor.GoogleMapsUrl }, JsonOptions); workOrder.FrozenPoc = JsonSerializer.Serialize( new WorkOrderFrozenPoc { Contacts = contacts, Notes = pocNotes }, JsonOptions); } public static WorkOrderFrozenSite? ParseSite(string? json) => Deserialize(json); public static WorkOrderFrozenCompany? ParseCompany(string? json) => Deserialize(json); public static WorkOrderFrozenPoc? ParsePoc(string? json) => Deserialize(json); private static Vendor? ResolveLiveVendor(Dispatch? dispatch) { var (vendorId, _) = WorkOrderBoardDispatchAssignment.LiveVendor( dispatch?.VendorId, dispatch?.Vendor?.CompanyName, dispatch?.Status); return vendorId.HasValue ? dispatch?.Vendor : null; } private static string? BuildMapsUrl(Locations location) { if (!double.TryParse(location.Latitude, NumberStyles.Float, CultureInfo.InvariantCulture, out var latitude) || !double.TryParse(location.Longitude, NumberStyles.Float, CultureInfo.InvariantCulture, out var longitude)) { return null; } return FormattableString.Invariant( $"https://www.google.com/maps/search/?api=1&query={latitude},{longitude}"); } private static string? JoinAddress(params string?[] parts) { var value = string.Join(", ", parts.Where(part => !string.IsNullOrWhiteSpace(part))); return string.IsNullOrWhiteSpace(value) ? null : value; } private static string? JoinName(params string?[] parts) { var value = string.Join(" ", parts.Where(part => !string.IsNullOrWhiteSpace(part))); return string.IsNullOrWhiteSpace(value) ? null : value; } private static string? FirstNotBlank(params string?[] values) => values.FirstOrDefault(value => !string.IsNullOrWhiteSpace(value))?.Trim(); private static void AddContact( ICollection contacts, string? name, string? phone) { if (string.IsNullOrWhiteSpace(name) && string.IsNullOrWhiteSpace(phone)) return; contacts.Add(new WorkOrderFrozenPocContact { Name = name?.Trim(), Phone = phone?.Trim() }); } private static T? Deserialize(string? json) { if (string.IsNullOrWhiteSpace(json)) return default; try { return JsonSerializer.Deserialize(json, JsonOptions); } catch (JsonException) { return default; } } } }