using System.Text.RegularExpressions;
using GeradoresService.Core;
namespace GeradoresService.Generators.Outros;
/// Matrículas portuguesas em todos os formatos desde 1937. Apenas formato.
public sealed partial class MatriculaGenerator : GeneratorBase
{
// K, W e Y não eram usadas nas matrículas portuguesas.
private const string Letters = "ABCDEFGHIJLMNOPQRSTUVXZ";
private sealed record Format(string Key, string Label, string Mask, string Period);
private static readonly Format[] Formats =
[
new("2020", "AA-00-AA (desde 2020)", "LL-DD-LL", "2020 – actualidade"),
new("2005", "00-AA-00 (2005–2020)", "DD-LL-DD", "2005 – 2020"),
new("1992", "00-00-AA (1992–2005)", "DD-DD-LL", "1992 – 2005"),
new("1937", "AA-00-00 (1937–1992)", "LL-DD-DD", "1937 – 1992"),
];
public override string Id => "matricula";
public override string Name => "Matrícula";
public override string Category => Categories.Outros;
public override string Description => "Matrícula automóvel portuguesa em qualquer um dos formatos.";
public override bool HasChecksum => false;
public override IReadOnlyList Options =>
[
Option("formato", "Formato", "2020", [.. Formats.Select(f => (f.Key, f.Label)), ("qualquer", "Qualquer")]),
];
public override GeneratedItem Generate(GeneratorContext context)
{
var key = context.Option(Options[0]);
var format = key == "qualquer" ? context.Pick(Formats) : Formats.Single(f => f.Key == key);
var plate = string.Concat(format.Mask.Select(c => c switch
{
'L' => Letters[context.Random.Next(Letters.Length)],
'D' => (char)('0' + context.Random.Next(10)),
_ => c,
}));
return new GeneratedItem(plate);
}
public override ValidationResult Validate(string value)
{
var plate = Checksums.Clean(value).ToUpperInvariant();
if (plate.Length != 6 || !plate.All(char.IsAsciiLetterOrDigit))
return ValidationResult.WrongFormat("Uma matrícula tem 6 caracteres em 3 pares (ex.: AA-00-AA).");
var mask = string.Concat(plate.Chunk(2).Select(p => p.All(char.IsAsciiDigit) ? "DD" : p.All(char.IsAsciiLetter) ? "LL" : "??"));
var masked = $"{mask[..2]}-{mask[2..4]}-{mask[4..]}";
var format = Formats.FirstOrDefault(f => f.Mask == masked);
if (format is null)
return ValidationResult.WrongFormat("Não corresponde a nenhum formato de matrícula portuguesa.");
var formatted = $"{plate[..2]}-{plate[2..4]}-{plate[4..]}";
if (plate.Any(c => c is 'K' or 'W' or 'Y'))
return ValidationResult.BadChecksum("As letras K, W e Y não são usadas em matrículas portuguesas.");
return ValidationResult.Valid(formatted, $"Matrícula válida (formato {format.Period}).", [$"Formato: {format.Label}"]);
}
}