using CredentialManager.Models; using DataConnection.CredentialManagement.Interfaces; using DataConnection.REST.Interfaces; using Microsoft.Extensions.Logging; namespace Data_Coupler.Services; /// /// Interfaccia per il servizio di sincronizzazione delle cancellazioni /// public interface IDeletionSyncService { /// /// Sincronizza le cancellazioni dalla sorgente alla destinazione /// Task SyncDeletionsAsync( List currentSourceKeyValues, string destinationEntity, string restCredentialName, IRestServiceClient restClient, DeletionSyncOptions options); } /// /// Servizio per la sincronizzazione delle cancellazioni dalla sorgente alla destinazione /// public class DeletionSyncService : IDeletionSyncService { private readonly IDataConnectionCredentialService _credentialService; private readonly ILogger _logger; public DeletionSyncService( IDataConnectionCredentialService credentialService, ILogger logger) { _credentialService = credentialService ?? throw new ArgumentNullException(nameof(credentialService)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } /// /// Sincronizza le cancellazioni dalla sorgente alla destinazione /// public async Task SyncDeletionsAsync( List currentSourceKeyValues, string destinationEntity, string restCredentialName, IRestServiceClient restClient, DeletionSyncOptions options) { var result = new DeletionSyncResult { StartTime = DateTime.Now }; try { _logger.LogInformation("Inizio sincronizzazione cancellazioni per {Entity} - {Credential}", destinationEntity, restCredentialName); // Step 1: Marca le associazioni come cancellate se non sono più presenti nella sorgente var markedCount = await _credentialService.MarkDeletedAssociationsAsync( currentSourceKeyValues, destinationEntity, restCredentialName); result.DeletedRecordsDetected = markedCount; _logger.LogInformation("Rilevati {Count} record cancellati dalla sorgente", markedCount); if (markedCount == 0) { result.IsSuccess = true; result.Message = "Nessun record cancellato rilevato"; result.EndTime = DateTime.Now; return result; } // Step 2: Ottieni le cancellazioni in attesa di sincronizzazione var pendingDeletions = await _credentialService.GetPendingDeletionsAsync( destinationEntity, restCredentialName); _logger.LogInformation("Trovate {Count} cancellazioni in attesa di sincronizzazione", pendingDeletions.Count); // Step 3: Esegui le cancellazioni nella destinazione foreach (var deletion in pendingDeletions) { try { bool syncSuccess = false; string errorMessage = ""; switch (options.Action) { case DeletionAction.Delete: // Elimina fisicamente il record syncSuccess = await DeleteRecordAsync( restClient, destinationEntity, deletion.DestinationId); break; case DeletionAction.Deactivate: // Marca il record come inattivo syncSuccess = await DeactivateRecordAsync( restClient, destinationEntity, deletion.DestinationId); break; case DeletionAction.Mark: // Imposta un campo personalizzato if (string.IsNullOrEmpty(options.MarkField) || string.IsNullOrEmpty(options.MarkValue)) { errorMessage = "MarkField e MarkValue devono essere specificati per DeletionAction.Mark"; _logger.LogWarning(errorMessage); result.Errors.Add($"KeyValue: {deletion.KeyValue} - {errorMessage}"); continue; } syncSuccess = await MarkRecordAsync( restClient, destinationEntity, deletion.DestinationId, options.MarkField, options.MarkValue); break; default: errorMessage = $"Azione di cancellazione non supportata: {options.Action}"; _logger.LogWarning(errorMessage); result.Errors.Add($"KeyValue: {deletion.KeyValue} - {errorMessage}"); continue; } if (syncSuccess) { // Marca la cancellazione come sincronizzata await _credentialService.MarkDeletionSyncedAsync(deletion.Id); result.DeletedRecordsSynced++; _logger.LogInformation( "Cancellazione sincronizzata: KeyValue={KeyValue}, DestinationId={DestinationId}, Action={Action}", deletion.KeyValue, deletion.DestinationId, options.Action); } else { result.SyncErrors++; var error = $"Errore nella sincronizzazione della cancellazione per KeyValue: {deletion.KeyValue}"; result.Errors.Add(error); _logger.LogWarning(error); } } catch (Exception ex) { result.SyncErrors++; var error = $"Errore durante la sincronizzazione della cancellazione per KeyValue: {deletion.KeyValue} - {ex.Message}"; result.Errors.Add(error); _logger.LogError(ex, "Errore nella sincronizzazione della cancellazione per {KeyValue}", deletion.KeyValue); } } result.IsSuccess = result.SyncErrors == 0; result.Message = result.IsSuccess ? $"Sincronizzazione completata: {result.DeletedRecordsSynced} record cancellati" : $"Sincronizzazione completata con errori: {result.DeletedRecordsSynced} sincronizzati, {result.SyncErrors} errori"; _logger.LogInformation(result.Message); } catch (Exception ex) { result.IsSuccess = false; result.Message = $"Errore durante la sincronizzazione delle cancellazioni: {ex.Message}"; result.Errors.Add(ex.Message); _logger.LogError(ex, "Errore durante la sincronizzazione delle cancellazioni"); } result.EndTime = DateTime.Now; return result; } /// /// Elimina fisicamente un record dalla destinazione /// private async Task DeleteRecordAsync( IRestServiceClient restClient, string entityName, string entityId) { try { return await restClient.DeleteEntityAsync(entityName, entityId); } catch (Exception ex) { _logger.LogError(ex, "Errore nell'eliminazione del record {EntityId} dall'entità {Entity}", entityId, entityName); return false; } } /// /// Marca un record come inattivo nella destinazione /// private async Task DeactivateRecordAsync( IRestServiceClient restClient, string entityName, string entityId) { try { var updateData = new Dictionary { { "IsActive", false }, { "Active", false } // Prova entrambi i campi comuni }; var result = await restClient.UpdateEntityAsync(entityName, entityId, updateData); return result != null; } catch (Exception ex) { _logger.LogError(ex, "Errore nella disattivazione del record {EntityId} dall'entità {Entity}", entityId, entityName); return false; } } /// /// Imposta un campo personalizzato per marcare un record come cancellato /// private async Task MarkRecordAsync( IRestServiceClient restClient, string entityName, string entityId, string markField, string markValue) { try { var updateData = new Dictionary { { markField, markValue } }; var result = await restClient.UpdateEntityAsync(entityName, entityId, updateData); return result != null; } catch (Exception ex) { _logger.LogError(ex, "Errore nella marcatura del record {EntityId} dall'entità {Entity}", entityId, entityName); return false; } } } /// /// Opzioni per la sincronizzazione delle cancellazioni /// public class DeletionSyncOptions { public DeletionAction Action { get; set; } = DeletionAction.Delete; public string? MarkField { get; set; } public string? MarkValue { get; set; } } /// /// Azione da eseguire per i record cancellati /// public enum DeletionAction { /// /// Elimina fisicamente il record /// Delete, /// /// Marca il record come inattivo /// Deactivate, /// /// Imposta un campo personalizzato /// Mark } /// /// Risultato della sincronizzazione delle cancellazioni /// public class DeletionSyncResult { public bool IsSuccess { get; set; } public string Message { get; set; } = ""; public int DeletedRecordsDetected { get; set; } public int DeletedRecordsSynced { get; set; } public int SyncErrors { get; set; } public List Errors { get; set; } = new(); public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } public TimeSpan Duration => EndTime - StartTime; }