using System.Globalization; using line_gestao_api.Data; using line_gestao_api.Models; using Microsoft.EntityFrameworkCore; namespace line_gestao_api.Services; public sealed class SpreadsheetImportAuditService { private const string DefaultResolution = "OVERRIDDEN_BY_GERAL"; private readonly AppDbContext _db; public SpreadsheetImportAuditService(AppDbContext db) { _db = db; } public SpreadsheetImportAuditSession StartRun(string? fileName, int sourceMaxItemGeral, int sourceValidCountGeral) { var canonicalTotalLinhas = sourceMaxItemGeral > 0 ? sourceMaxItemGeral : sourceValidCountGeral; var run = new ImportAuditRun { Id = Guid.NewGuid(), ImportedAt = DateTime.UtcNow, FileName = string.IsNullOrWhiteSpace(fileName) ? null : fileName.Trim(), Status = "RUNNING", CanonicalTotalLinhas = canonicalTotalLinhas, SourceMaxItemGeral = sourceMaxItemGeral, SourceValidCountGeral = sourceValidCountGeral, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; return new SpreadsheetImportAuditSession(run); } public int CanonicalizeTotalLinhas( SpreadsheetImportAuditSession session, string entity, string fieldName, int? sourceValue, string severity = "WARNING") { ArgumentNullException.ThrowIfNull(session); var canonicalValue = session.Run.CanonicalTotalLinhas; if (sourceValue != canonicalValue) { session.Issues.Add(new ImportAuditIssue { Id = Guid.NewGuid(), AuditRunId = session.Run.Id, Entity = entity, FieldName = fieldName, SourceValue = sourceValue.HasValue ? sourceValue.Value.ToString(CultureInfo.InvariantCulture) : null, CanonicalValue = canonicalValue.ToString(CultureInfo.InvariantCulture), Resolution = DefaultResolution, Severity = string.IsNullOrWhiteSpace(severity) ? "WARNING" : severity.Trim().ToUpperInvariant(), CreatedAt = DateTime.UtcNow }); } return canonicalValue; } public async Task SaveRunAsync( SpreadsheetImportAuditSession session, string status = "SUCCESS", CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(session); session.Run.Status = string.IsNullOrWhiteSpace(status) ? "SUCCESS" : status.Trim().ToUpperInvariant(); session.Run.UpdatedAt = DateTime.UtcNow; _db.ImportAuditRuns.Add(session.Run); if (session.Issues.Count > 0) { _db.ImportAuditIssues.AddRange(session.Issues); } await _db.SaveChangesAsync(cancellationToken); } public async Task GetCanonicalTotalLinhasForReadAsync(CancellationToken cancellationToken = default) { try { var fromLatestRun = await _db.ImportAuditRuns .AsNoTracking() .OrderByDescending(x => x.ImportedAt) .ThenByDescending(x => x.Id) .Select(x => (int?)x.CanonicalTotalLinhas) .FirstOrDefaultAsync(cancellationToken); if (fromLatestRun.HasValue && fromLatestRun.Value > 0) { return fromLatestRun.Value; } } catch { // Fallback para evitar indisponibilidade caso a migration ainda não tenha sido aplicada. } return await CalculateCanonicalTotalLinhasFromGeralAsync(cancellationToken); } public async Task CalculateCanonicalTotalLinhasFromGeralAsync(CancellationToken cancellationToken = default) { var maxItem = await _db.MobileLines .AsNoTracking() .MaxAsync(x => (int?)x.Item, cancellationToken); if (maxItem.HasValue && maxItem.Value > 0) { return maxItem.Value; } return await _db.MobileLines.AsNoTracking().CountAsync(cancellationToken); } } public sealed class SpreadsheetImportAuditSession { internal SpreadsheetImportAuditSession(ImportAuditRun run) { Run = run; } public ImportAuditRun Run { get; } public List Issues { get; } = new(); public int CanonicalTotalLinhas => Run.CanonicalTotalLinhas; }