using IceImportDAL.DTO.IceImportPipeline; using Microsoft.Extensions.Logging; namespace IceImportBLL.FieldResolvers; // ValueType = 4 (Code -> Id lookup). Consults the pre-resolved lookup dictionary populated once, // up front, by IEntityLookupService.ResolveAllLookupsAsync — zero further I/O per row (this is // what eliminates legacy's per-row/file-rewrite lookup pattern). // // IceMapDetails.EntityId identifies which entity's code is being resolved (distinct from // DestinationMemberEntityId, which identifies where the resolved id gets written). public class CodeToIdLookupResolver : IIceFieldValueResolver { private readonly ILogger _logger; public CodeToIdLookupResolver(ILogger logger) => _logger = logger; public int ValueType => 4; public Task ResolveAsync(FieldResolutionContext ctx, CancellationToken ct) { try { var fieldName = ctx.DetailConfig.IceMapDetailsSourceFieldName?.Trim().ToUpperInvariant(); string? raw = null; if (!string.IsNullOrEmpty(fieldName) && ctx.SourceRow.Table.Columns.Contains(fieldName)) raw = ctx.SourceRow[fieldName]?.ToString()?.Trim(); else if (ctx.DetailConfig.IceMapDetailsIsOptional == 0) // Optional field whose source column isn't present in this file — fall back to the // configured default code, then resolve it through the same Code -> Id lookup below. raw = ctx.DetailConfig.IceMapDetailsOptionalFiledValue?.Trim(); if (string.IsNullOrEmpty(raw)) return Task.FromResult(FieldResolutionResult.Ok(null)); if (ctx.Lookups.TryGetValue(ctx.DetailConfig.EntityId, out var byCode) && byCode.TryGetValue(raw, out var id)) return Task.FromResult(FieldResolutionResult.Ok(id)); // Error, not Warning — an unresolved Code -> Id lookup means this field would otherwise // be committed with a null/invalid FK, so the whole row must be rejected rather than // silently saved with bad data. var error = new IceImportFieldErrorDTO { RowNumber = ctx.RowNumber, EntityCode = ctx.DetailConfig.EntityCode ?? string.Empty, FieldName = ctx.DetailConfig.IceMapDetailsSourceFieldName ?? fieldName ?? string.Empty, Message = $"Code '{raw}' could not be resolved to an existing {ctx.DetailConfig.EntityCode ?? "record"}.", Severity = IceImportSeverity.Error, Value = raw }; return Task.FromResult(FieldResolutionResult.WithWarning(null, error)); } catch (Exception ex) { _logger.LogError(ex, "IceImport: CodeToIdLookupResolver failed for Row {RowNumber}", ctx.RowNumber); var error = new IceImportFieldErrorDTO { RowNumber = ctx.RowNumber, EntityCode = ctx.DetailConfig.EntityCode ?? string.Empty, FieldName = ctx.DetailConfig.IceMapDetailsSourceFieldName ?? string.Empty, Message = $"Unexpected error resolving Code -> Id: {ex.Message}", Severity = IceImportSeverity.Error }; return Task.FromResult(FieldResolutionResult.WithWarning(null, error)); } } }