using System.Text.RegularExpressions; namespace SeaHaven.Services.Helpers { public static class WorkOrderNumberNormalizer { private const int RequiredLength = 11; private const string ProvisionalPrefix = "SH"; private const int MinimumProvisionalDigits = 5; public static bool TryNormalize(string? input, out string normalized, out string? error) { normalized = ""; error = null; if (string.IsNullOrWhiteSpace(input)) { error = "WO number is required."; return false; } var trimmed = input.Trim(); if (WorkOrderNumberRules.IsProvisional(trimmed)) return TryNormalizeProvisional(trimmed, out normalized, out error); var digits = Regex.Replace(trimmed, @"\D", ""); if (digits.Length == 0) { error = "WO number must contain digits."; return false; } if (digits.Length > RequiredLength) { error = $"WO number cannot exceed {RequiredLength} digits."; return false; } normalized = digits.PadLeft(RequiredLength, '0'); return true; } // SH-320: an SH-prefixed number is the documented placeholder for a WO still // awaiting its real APM number; keep the prefix instead of stripping it to digits. private static bool TryNormalizeProvisional(string trimmed, out string normalized, out string? error) { normalized = ""; error = null; var digits = Regex.Replace(trimmed[ProvisionalPrefix.Length..], @"\D", ""); if (digits.Length == 0) { error = "WO number must contain digits."; return false; } var candidate = ProvisionalPrefix + digits.PadLeft(MinimumProvisionalDigits, '0'); if (candidate.Length > RequiredLength) { error = $"WO number cannot exceed {RequiredLength} characters."; return false; } normalized = candidate; return true; } } }