line-gestao-api/Services/SpreadsheetImportAuditServi...

143 lines
4.4 KiB
C#

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<int> 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<int> 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<ImportAuditIssue> Issues { get; } = new();
public int CanonicalTotalLinhas => Run.CanonicalTotalLinhas;
}