line-gestao-api/Services/MveAuditNormalization.cs

294 lines
9.8 KiB
C#

using System.Globalization;
using System.Text;
namespace line_gestao_api.Services;
internal static class MveAuditNormalization
{
public static string NormalizeHeader(string? value)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}
var normalized = value.Trim().ToUpperInvariant().Normalize(NormalizationForm.FormD);
var builder = new StringBuilder(normalized.Length);
foreach (var ch in normalized)
{
if (CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark)
{
builder.Append(ch);
}
}
return builder.ToString()
.Replace("\u00A0", " ")
.Trim();
}
public static string CleanTextValue(string? value, bool removeSingleQuotes = true)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}
var cleaned = value
.Replace("\u00A0", " ")
.Replace("\t", " ")
.Replace("\r", " ")
.Replace("\n", " ")
.Trim();
if (removeSingleQuotes)
{
cleaned = cleaned.Replace("'", string.Empty);
}
while (cleaned.Contains(" ", StringComparison.Ordinal))
{
cleaned = cleaned.Replace(" ", " ", StringComparison.Ordinal);
}
return cleaned.Trim();
}
public static string OnlyDigits(string? value)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}
var builder = new StringBuilder(value.Length);
foreach (var ch in value)
{
if (char.IsDigit(ch))
{
builder.Append(ch);
}
}
return builder.ToString();
}
public static string? NullIfEmptyDigits(string? value)
{
var digits = OnlyDigits(value);
return string.IsNullOrWhiteSpace(digits) ? null : digits;
}
public static string NormalizeComparableText(string? value)
{
var cleaned = CleanTextValue(value);
if (string.IsNullOrWhiteSpace(cleaned))
{
return string.Empty;
}
return NormalizeHeader(cleaned)
.Replace(" ", " ", StringComparison.Ordinal)
.Trim();
}
public static string NormalizeAccountLike(string? value)
{
var digits = OnlyDigits(value);
if (!string.IsNullOrWhiteSpace(digits))
{
return digits;
}
return NormalizeComparableText(value);
}
public static DateTime? ParseDateValue(string? rawValue)
{
var cleaned = CleanTextValue(rawValue);
if (string.IsNullOrWhiteSpace(cleaned))
{
return null;
}
if (double.TryParse(
cleaned.Replace(",", ".", StringComparison.Ordinal),
NumberStyles.Float,
CultureInfo.InvariantCulture,
out var oaValue) &&
oaValue > 10_000 &&
oaValue < 90_000)
{
try
{
return ToUtcDateOnly(DateTime.FromOADate(oaValue));
}
catch
{
// segue para os demais formatos
}
}
var formats = new[]
{
"dd/MM/yyyy",
"d/M/yyyy",
"dd/MM/yy",
"d/M/yy",
"yyyy-MM-dd",
"dd-MM-yyyy",
"d-M-yyyy",
"yyyyMMdd"
};
foreach (var format in formats)
{
if (DateTime.TryParseExact(
cleaned,
format,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out var exact))
{
return ToUtcDateOnly(exact);
}
}
if (DateTime.TryParse(cleaned, new CultureInfo("pt-BR"), DateTimeStyles.None, out var parsedBr))
{
return ToUtcDateOnly(parsedBr);
}
if (DateTime.TryParse(cleaned, CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedInvariant))
{
return ToUtcDateOnly(parsedInvariant);
}
return null;
}
public static DateTime ToUtcDateOnly(DateTime date)
{
return new DateTime(date.Year, date.Month, date.Day, 12, 0, 0, DateTimeKind.Utc);
}
public static string FormatDate(DateTime? value)
{
return value.HasValue ? value.Value.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture) : string.Empty;
}
public static MveNormalizedStatus NormalizeReportStatus(string? rawValue)
{
var displayValue = CleanTextValue(rawValue);
if (string.IsNullOrWhiteSpace(displayValue))
{
return new MveNormalizedStatus(string.Empty, string.Empty, false);
}
var headSegment = NormalizeComparableText(displayValue.Split(':', 2)[0])
.Replace("/", " ", StringComparison.Ordinal)
.Replace("-", " ", StringComparison.Ordinal)
.Replace(".", " ", StringComparison.Ordinal)
.Replace("(", " ", StringComparison.Ordinal)
.Replace(")", " ", StringComparison.Ordinal)
.Replace(" ", " ", StringComparison.Ordinal)
.Trim();
var canonical = NormalizeComparableText(displayValue)
.Replace("/", " ", StringComparison.Ordinal)
.Replace("-", " ", StringComparison.Ordinal)
.Replace(".", " ", StringComparison.Ordinal)
.Replace("(", " ", StringComparison.Ordinal)
.Replace(")", " ", StringComparison.Ordinal)
.Replace(" ", " ", StringComparison.Ordinal)
.Trim();
var key = headSegment switch
{
var text when text.Contains("ATIVO", StringComparison.Ordinal) || text == "ATIVA" => "ATIVO",
var text when text.Contains("BLOQUEIO PARCIAL", StringComparison.Ordinal) => "BLOQUEIO_PERDA_ROUBO",
var text when text.Contains("CANCEL", StringComparison.Ordinal) => "BLOQUEIO_120_DIAS",
var text when text.Contains("SUSPENS", StringComparison.Ordinal) => "SUSPENSO",
var text when text.Contains("PENDENTE", StringComparison.Ordinal) &&
text.Contains("TROCA", StringComparison.Ordinal) &&
text.Contains("NUMERO", StringComparison.Ordinal) => "PENDENTE_TROCA_NUMERO",
var text when text.Contains("PERDA", StringComparison.Ordinal) || text.Contains("ROUBO", StringComparison.Ordinal) => "BLOQUEIO_PERDA_ROUBO",
var text when text.Contains("BLOQUEIO", StringComparison.Ordinal) && text.Contains("120", StringComparison.Ordinal) => "BLOQUEIO_120_DIAS",
_ => canonical.Replace(" ", "_", StringComparison.Ordinal)
};
var recognized = key is
"ATIVO" or
"BLOQUEIO_PERDA_ROUBO" or
"BLOQUEIO_120_DIAS" or
"SUSPENSO" or
"PENDENTE_TROCA_NUMERO";
return new MveNormalizedStatus(displayValue, key, recognized);
}
public static MveNormalizedStatus NormalizeSystemStatus(string? rawValue)
{
var displayValue = CleanTextValue(rawValue);
if (string.IsNullOrWhiteSpace(displayValue))
{
return new MveNormalizedStatus(string.Empty, string.Empty, false);
}
var canonical = NormalizeComparableText(displayValue)
.Replace("/", " ", StringComparison.Ordinal)
.Replace("-", " ", StringComparison.Ordinal)
.Replace(".", " ", StringComparison.Ordinal)
.Replace(":", " ", StringComparison.Ordinal)
.Replace("(", " ", StringComparison.Ordinal)
.Replace(")", " ", StringComparison.Ordinal)
.Replace(" ", " ", StringComparison.Ordinal)
.Trim();
var key = canonical switch
{
var text when text.Contains("ATIVO", StringComparison.Ordinal) || text == "ATIVA" => "ATIVO",
var text when text.Contains("PERDA", StringComparison.Ordinal) || text.Contains("ROUBO", StringComparison.Ordinal) => "BLOQUEIO_PERDA_ROUBO",
var text when text.Contains("BLOQUEIO PARCIAL", StringComparison.Ordinal) => "BLOQUEIO_PERDA_ROUBO",
var text when text.Contains("BLOQUEIO", StringComparison.Ordinal) && text.Contains("120", StringComparison.Ordinal) => "BLOQUEIO_120_DIAS",
var text when text.Contains("CANCEL", StringComparison.Ordinal) => "CANCELADO",
var text when text.Contains("SUSPENS", StringComparison.Ordinal) => "SUSPENSO",
var text when text.Contains("PENDENTE", StringComparison.Ordinal) &&
text.Contains("TROCA", StringComparison.Ordinal) &&
text.Contains("NUMERO", StringComparison.Ordinal) => "PENDENTE_TROCA_NUMERO",
_ => canonical.Replace(" ", "_", StringComparison.Ordinal)
};
var recognized = key is
"ATIVO" or
"BLOQUEIO_PERDA_ROUBO" or
"BLOQUEIO_120_DIAS" or
"CANCELADO" or
"SUSPENSO" or
"PENDENTE_TROCA_NUMERO";
return new MveNormalizedStatus(displayValue, key, recognized);
}
public static MveNormalizedStatus NormalizeStatus(string? rawValue)
{
return NormalizeSystemStatus(rawValue);
}
public static string NormalizeStatusForSystem(string? rawValue)
{
var normalized = NormalizeReportStatus(rawValue);
return normalized.Key switch
{
"ATIVO" => "ATIVO",
"BLOQUEIO_PERDA_ROUBO" => "BLOQUEIO PERDA/ROUBO",
"BLOQUEIO_120_DIAS" => "BLOQUEIO 120 DIAS",
"SUSPENSO" => "SUSPENSO",
"PENDENTE_TROCA_NUMERO" => "PENDENTE TROCA NUMERO",
_ => normalized.DisplayValue
};
}
}
internal sealed record MveNormalizedStatus(string DisplayValue, string Key, bool Recognized);