using CredentialManager.Data;
using CredentialManager.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace CredentialManager.Services;
///
/// Servizio per la gestione delle associazioni tra record sorgente e destinazione
///
public class RecordAssociationService : IRecordAssociationService
{
private readonly CredentialDbContext _context;
private readonly ILogger _logger;
public RecordAssociationService(
CredentialDbContext context,
ILogger logger)
{
_context = context;
_logger = logger;
}
public async Task SaveAssociationAsync(RecordAssociation association)
{
try
{
// Controlla se esiste già un'associazione per questa combinazione
var existing = await _context.RecordAssociations
.FirstOrDefaultAsync(ra =>
ra.SourceName == association.SourceName &&
ra.SourceKey == association.SourceKey &&
ra.DestinationEntity == association.DestinationEntity &&
ra.IsActive);
if (existing != null)
{
// Aggiorna l'associazione esistente
existing.DestinationId = association.DestinationId;
existing.RestCredentialName = association.RestCredentialName;
existing.UpdatedAt = DateTime.UtcNow;
existing.AdditionalInfo = association.AdditionalInfo;
_context.RecordAssociations.Update(existing);
await _context.SaveChangesAsync();
_logger.LogInformation("Associazione aggiornata: {SourceName}/{SourceKey} -> {DestinationEntity}/{DestinationId}",
association.SourceName, association.SourceKey, association.DestinationEntity, association.DestinationId);
return existing.Id;
}
else
{
// Crea nuova associazione
_context.RecordAssociations.Add(association);
await _context.SaveChangesAsync();
_logger.LogInformation("Nuova associazione creata: {SourceName}/{SourceKey} -> {DestinationEntity}/{DestinationId}",
association.SourceName, association.SourceKey, association.DestinationEntity, association.DestinationId);
return association.Id;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel salvare l'associazione: {SourceName}/{SourceKey} -> {DestinationEntity}",
association.SourceName, association.SourceKey, association.DestinationEntity);
throw;
}
}
public async Task FindAssociationAsync(string sourceName, string sourceKey, string destinationEntity)
{
try
{
return await _context.RecordAssociations
.FirstOrDefaultAsync(ra =>
ra.SourceName == sourceName &&
ra.SourceKey == sourceKey &&
ra.DestinationEntity == destinationEntity &&
ra.IsActive);
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nella ricerca dell'associazione: {SourceName}/{SourceKey} -> {DestinationEntity}",
sourceName, sourceKey, destinationEntity);
throw;
}
}
public async Task> GetAssociationsBySourceAsync(string sourceName, string sourceType)
{
try
{
return await _context.RecordAssociations
.Where(ra => ra.SourceName == sourceName && ra.SourceType == sourceType && ra.IsActive)
.OrderByDescending(ra => ra.CreatedAt)
.ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel recupero delle associazioni per sorgente: {SourceName} ({SourceType})",
sourceName, sourceType);
throw;
}
}
public async Task> GetAssociationsByDestinationAsync(string destinationEntity, string restCredentialName)
{
try
{
return await _context.RecordAssociations
.Where(ra => ra.DestinationEntity == destinationEntity &&
ra.RestCredentialName == restCredentialName &&
ra.IsActive)
.OrderByDescending(ra => ra.CreatedAt)
.ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel recupero delle associazioni per destinazione: {DestinationEntity} ({RestCredentialName})",
destinationEntity, restCredentialName);
throw;
}
}
public async Task> GetAllActiveAssociationsAsync()
{
try
{
return await _context.RecordAssociations
.Where(ra => ra.IsActive)
.OrderByDescending(ra => ra.CreatedAt)
.ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel recupero di tutte le associazioni attive");
throw;
}
}
public async Task UpdateAssociationAsync(RecordAssociation association)
{
try
{
var existing = await _context.RecordAssociations.FindAsync(association.Id);
if (existing == null)
{
_logger.LogWarning("Associazione con ID {Id} non trovata per l'aggiornamento", association.Id);
return false;
}
existing.DestinationId = association.DestinationId;
existing.RestCredentialName = association.RestCredentialName;
existing.UpdatedAt = DateTime.UtcNow;
existing.AdditionalInfo = association.AdditionalInfo;
existing.IsActive = association.IsActive;
_context.RecordAssociations.Update(existing);
await _context.SaveChangesAsync();
_logger.LogInformation("Associazione aggiornata: ID {Id}", association.Id);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nell'aggiornamento dell'associazione: ID {Id}", association.Id);
throw;
}
}
public async Task DeactivateAssociationAsync(int id)
{
try
{
var association = await _context.RecordAssociations.FindAsync(id);
if (association == null)
{
_logger.LogWarning("Associazione con ID {Id} non trovata per la disattivazione", id);
return false;
}
association.IsActive = false;
association.UpdatedAt = DateTime.UtcNow;
_context.RecordAssociations.Update(association);
await _context.SaveChangesAsync();
_logger.LogInformation("Associazione disattivata: ID {Id}", id);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nella disattivazione dell'associazione: ID {Id}", id);
throw;
}
}
public async Task DeleteAssociationAsync(int id)
{
try
{
var association = await _context.RecordAssociations.FindAsync(id);
if (association == null)
{
_logger.LogWarning("Associazione con ID {Id} non trovata per l'eliminazione", id);
return false;
}
_context.RecordAssociations.Remove(association);
await _context.SaveChangesAsync();
_logger.LogInformation("Associazione eliminata: ID {Id}", id);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nell'eliminazione dell'associazione: ID {Id}", id);
throw;
}
}
public async Task CleanupOldAssociationsAsync(TimeSpan olderThan)
{
try
{
var cutoffDate = DateTime.UtcNow - olderThan;
var oldAssociations = await _context.RecordAssociations
.Where(ra => ra.CreatedAt < cutoffDate && !ra.IsActive)
.ToListAsync();
if (oldAssociations.Any())
{
_context.RecordAssociations.RemoveRange(oldAssociations);
await _context.SaveChangesAsync();
_logger.LogInformation("Pulite {Count} associazioni obsolete più vecchie di {Cutoff}",
oldAssociations.Count, cutoffDate);
}
return oldAssociations.Count;
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nella pulizia delle associazioni obsolete");
throw;
}
}
}