using System.Text.RegularExpressions; using Microsoft.EntityFrameworkCore; using OTSSignsOrchestrator.Server.Data; namespace OTSSignsOrchestrator.Server.Services; public class AbbreviationService { private static readonly HashSet StopWords = new(StringComparer.OrdinalIgnoreCase) { "inc", "llc", "ltd", "co", "corp", "group", "signs", "digital", "media", "the", "and", "of", "a" }; private readonly OrchestratorDbContext _db; private readonly ILogger _logger; public AbbreviationService(OrchestratorDbContext db, ILogger logger) { _db = db; _logger = logger; } public async Task GenerateAsync(string companyName) { var words = Regex.Split(companyName.Trim(), @"\s+") .Select(w => Regex.Replace(w, @"[^a-zA-Z0-9]", "")) .Where(w => w.Length > 0 && !StopWords.Contains(w)) .ToList(); if (words.Count == 0) throw new InvalidOperationException( $"Cannot generate abbreviation from company name '{companyName}' — no usable words after filtering."); string abbrev; if (words.Count >= 3) { // Take first letter of first 3 words abbrev = string.Concat(words.Take(3).Select(w => w[0])); } else if (words.Count == 2) { // First letter of each word + second char of last word abbrev = $"{words[0][0]}{words[1][0]}{(words[1].Length > 1 ? words[1][1] : words[0][1])}"; } else { // Single word — take up to 3 chars abbrev = words[0].Length >= 3 ? words[0][..3] : words[0].PadRight(3, 'X'); } abbrev = Regex.Replace(abbrev.ToUpperInvariant(), @"[^A-Z0-9]", ""); if (abbrev.Length > 3) abbrev = abbrev[..3]; // Check uniqueness if (!await _db.Customers.AnyAsync(c => c.Abbreviation == abbrev)) { _logger.LogInformation("Generated abbreviation {Abbrev} for '{CompanyName}'", abbrev, companyName); return abbrev; } // Collision — try suffix 2–9 var prefix = abbrev[..2]; for (var suffix = 2; suffix <= 9; suffix++) { var candidate = $"{prefix}{suffix}"; if (!await _db.Customers.AnyAsync(c => c.Abbreviation == candidate)) { _logger.LogInformation("Generated abbreviation {Abbrev} (collision resolved) for '{CompanyName}'", candidate, companyName); return candidate; } } throw new InvalidOperationException( $"All abbreviation variants for '{companyName}' are taken ({prefix}2–{prefix}9)."); } }