using GeradoresService.Core; using GeradoresService.Generators.Contactos; using GeradoresService.Generators.Financeiro; using GeradoresService.Generators.Identificacao; using GeradoresService.Generators.Outros; namespace GeradoresService; public sealed record DetectionMatch(IGenerator Generator, ValidationResult Result); public sealed class GeneratorRegistry { public const int MaxBatch = 1000; public IReadOnlyList All { get; } public GeneratorRegistry() : this( [ new NifGenerator(), new NipcGenerator(), new NissGenerator(), new CartaoCidadaoGenerator(), new PassaporteGenerator(), new IbanGenerator(), new NibGenerator(), new CartaoCreditoGenerator(), new ReferenciaMultibancoGenerator(), new PessoaGenerator(), new TelefoneGenerator(), new CodigoPostalGenerator(), new EmailGenerator(), new MatriculaGenerator(), new EanGenerator(), new UuidGenerator(), ]) { } public GeneratorRegistry(IReadOnlyList generators) => All = generators; public IGenerator? Find(string id) => All.FirstOrDefault(g => string.Equals(g.Id, id, StringComparison.OrdinalIgnoreCase)); /// Gera valores. Um torna o resultado reprodutível. public IReadOnlyList Generate(IGenerator generator, int count, IReadOnlyDictionary options, int? seed = null) { if (count is < 1 or > MaxBatch) throw new ArgumentOutOfRangeException(nameof(count), $"A quantidade deve estar entre 1 e {MaxBatch}."); var context = new GeneratorContext(seed is { } s ? new Random(s) : Random.Shared, options); var items = new GeneratedItem[count]; for (var i = 0; i < count; i++) items[i] = generator.Generate(context); return items; } /// /// Validador livre: tenta todos os tipos. Devolve primeiro os válidos, depois os que têm o formato /// certo mas falham o controlo (ex.: "parece um NIF mas o dígito está errado"). /// public IReadOnlyList Detect(string value) { if (string.IsNullOrWhiteSpace(value)) return []; return All .Where(g => g.CanValidate) .Select(g => new DetectionMatch(g, SafeValidate(g, value))) .Where(m => m.Result.FormatMatch) .OrderByDescending(m => m.Result.IsValid) .ThenByDescending(m => m.Generator.HasChecksum) .ToList(); } private static ValidationResult SafeValidate(IGenerator generator, string value) { try { return generator.Validate(value); } catch (Exception ex) when (ex is FormatException or ArgumentException or OverflowException) { return ValidationResult.WrongFormat(ex.Message); } } }