using GeradoresService.Core; namespace GeradoresService.Generators.Identificacao; /// /// Número de documento do Cartão de Cidadão: NNNNNNNN C VV T /// - NNNNNNNN: número de identificação civil (NIC) /// - C: dígito de controlo do NIC (módulo 11) /// - VV: versão (duas letras/dígitos) /// - T: dígito de controlo do documento completo (Luhn com A=10..Z=35), conforme especificação da AMA. /// public sealed class CartaoCidadaoGenerator : GeneratorBase { public override string Id => "cc"; public override string Name => "Cartão de Cidadão"; public override string Category => Categories.Identificacao; public override string Description => "Número de documento do Cartão de Cidadão."; public override IReadOnlyList Options => [ Option("formato", "Formato", "espacos", ("espacos", "12345678 9 ZZ1"), ("compacto", "123456789ZZ1")), ]; public override GeneratedItem Generate(GeneratorContext context) { var nic = context.Digits(8); var c = Checksums.Mod11(nic); // As versões começam em ZZ e vão decrementando. var version = "Z" + (char)('A' + context.Random.Next(26)); var payload = $"{nic}{c}{version}"; var t = Checksums.LuhnCheckDigit(payload); var compact = payload + t; return new GeneratedItem(context.Option(Options[0]) == "compacto" ? compact : Format(compact)); } private static string Format(string compact) => $"{compact[..8]} {compact[8]} {compact[9..]}"; public override ValidationResult Validate(string value) { var cc = Checksums.Clean(value).ToUpperInvariant(); if (cc.Length != 12 || !Checksums.AllDigits(cc[..9]) || !cc[9..11].All(char.IsAsciiLetterOrDigit) || !char.IsAsciiDigit(cc[11])) return ValidationResult.WrongFormat("Formato esperado: 8 dígitos, 1 dígito, 2 letras/dígitos de versão e 1 dígito (ex.: 00000000 0 ZZ4)."); var details = new List { $"NIC: {cc[..8]}", $"Versão: {cc[9..11]}", "Controlo: algoritmo Luhn sobre os 12 caracteres (A=10 … Z=35)", }; if (!Checksums.LuhnValid(cc)) { var expected = Checksums.LuhnCheckDigit(cc[..11]); return ValidationResult.BadChecksum($"Dígito de controlo inválido: esperado {expected}, encontrado {cc[11]}.", details); } return ValidationResult.Valid(Format(cc), "Número de documento do CC válido.", details); } }