using GeradoresService.Core; namespace GeradoresService.Generators.Outros; /// Códigos de barras EAN-13 / EAN-8 (GS1). Controlo: pesos 3,1,3,1… a partir da direita. public sealed class EanGenerator : GeneratorBase { public override string Id => "ean"; public override string Name => "EAN / Código de barras"; public override string Category => Categories.Outros; public override string Description => "Códigos EAN-13 e EAN-8 com dígito de controlo GS1."; public override IReadOnlyList Options => [ Option("tipo", "Tipo", "ean13", ("ean13", "EAN-13"), ("ean8", "EAN-8")), Option("prefixo", "Prefixo GS1", "560", ("560", "560 — Portugal"), ("qualquer", "Qualquer")), ]; public override GeneratedItem Generate(GeneratorContext context) { var length = context.Option(Options[0]) == "ean8" ? 8 : 13; var prefix = context.Option(Options[1]) == "560" ? "560" : context.Digits(3); var body = prefix + context.Digits(length - 1 - prefix.Length); return new GeneratedItem(body + CheckDigit(body)); } public static int CheckDigit(string payload) { var sum = 0; for (var i = 0; i < payload.Length; i++) { var weight = (payload.Length - i) % 2 == 1 ? 3 : 1; sum += (payload[i] - '0') * weight; } return (10 - sum % 10) % 10; } public override ValidationResult Validate(string value) { var ean = Checksums.Clean(value); if (ean.Length is not (8 or 13) || !Checksums.AllDigits(ean)) return ValidationResult.WrongFormat("Um EAN tem 8 ou 13 dígitos."); var expected = CheckDigit(ean[..^1]); var details = new List { $"Tipo: EAN-{ean.Length}" }; if (ean.Length == 13 && ean.StartsWith("560")) details.Add("Prefixo 560: Portugal"); return expected == ean[^1] - '0' ? ValidationResult.Valid(ean, $"EAN-{ean.Length} válido.", details) : ValidationResult.BadChecksum($"Dígito de controlo inválido: esperado {expected}, encontrado {ean[^1]}.", details); } }