using adas_core.Application.Exceptions; using adas_core.Application.Repositories.Interfaces; using adas_core.Application.Services.Interfaces; using adas_core.Domain.Enums; using adas_core.Domain.Models.MongoModels; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using MongoDB.Bson; using MongoDB.Driver; namespace adas_core.Application.Services; public class HistoricalConfigChangesService( IHistoricalConfigChangesRepository historicalConfigChangesRepository, ILogger logger, IHttpContextAccessor httpContextAccessor, ILocalAuditService auditService) : IHistoricalConfigChangesService { private readonly ILogger _logger = logger; /// /// Deletes a historical configuration change record by its identifier and creates an audit log entry recording the deletion. /// /// The unique identifier of the historical configuration change to delete. public async Task DeleteHistoricalConfigChange(ObjectId id) { var filter = Builders.Filter.Eq("_id", id); var result = historicalConfigChangesRepository.FindById(id); await historicalConfigChangesRepository.Collection.DeleteOneAsync(filter); _logger.LogInformation("Deleted historicalConfigChanges with id: {id}", id); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, result, null); } /// /// Retrieves the most recent historical configuration change entry for the specified configuration type. /// /// The configuration type used to look up the last historical change. /// The most recent entry, or null if no changes exist for the given type. public async Task FindLastConfigChanges(DisplayConfigEnums.ConfigTypes configType) { var result = await historicalConfigChangesRepository.FindLastHistoricalConfigChangesByType(configType); return result.FirstOrDefault(); } /// /// Retrieves a historical configuration change record by its unique identifier. /// Returns null when no matching record is found in the repository. /// /// The unique identifier of the historical configuration change to retrieve. /// The matching record, or null if no record is found. public async Task Get(ObjectId id) { return await historicalConfigChangesRepository.FindById(id); } /// /// Retrieves all historical configuration changes from the repository. /// /// A task that represents the asynchronous operation, containing a collection of all records. public async Task> GetAll() { return await historicalConfigChangesRepository.FindAll(); } /// /// Retrieves the most recent historical configuration changes for the specified configuration type, limited to a given number of entries. /// /// The configuration type used to filter the historical changes. /// The maximum number of recent changes to return. Defaults to 10. /// A collection of the latest entries matching the specified type. public async Task> GetByType(DisplayConfigEnums.ConfigTypes type, int num = 10) { return await historicalConfigChangesRepository.FindLastHistoricalConfigChangesByType(type, num); } /// /// Retrieves the most recent historical configuration changes for a given user, optionally filtered by configuration type and limited to a specified maximum number of entries. /// /// The identifier of the user whose historical configuration changes are being retrieved. /// Optional filter for the configuration type; when null, all configuration types are included. /// The maximum number of historical change entries to return. Defaults to 10. /// A task that represents the asynchronous operation, containing a collection of the user's historical configuration changes. public async Task> GetByUser(string user, DisplayConfigEnums.ConfigTypes? configTypes = null, int num = 10) { return await historicalConfigChangesRepository.FindLastHistoricalConfigChangesByUser(user, configTypes, num); } /// /// Inserts a new historical configuration change record into the repository and creates a corresponding audit log entry. /// If the repository returns null, a conflict exception is thrown; on failure, the error is logged and null is returned. /// /// The historical configuration change entity to insert. /// The inserted entity, or null if the operation fails. /// Thrown when the repository returns null after the insert operation. public async Task InsertOne(HistoricalConfigChanges historicalConfigChanges) { try { var result = await historicalConfigChangesRepository.InsertOneAsync(historicalConfigChanges) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictCreationFailed); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, result); return await historicalConfigChangesRepository.InsertOneAsync(historicalConfigChanges); } catch (Exception ex) { _logger.LogError("Exception inserting historicalConfigChanges {changes} exception:{e} ", historicalConfigChanges.ToJson(), ex); return null; } } /// /// Updates an existing historical configuration change record, creating an audit log entry for the change. /// If the record is not found, a is thrown; any other exception is logged and the method returns null. /// /// The historical configuration change entity containing the updated values to persist. /// The updated entity on success, or null if an error occurs during the operation. /// Thrown when no existing historical configuration change is found with the specified Id. public async Task UpdateHistoricalConfigChange( HistoricalConfigChanges historicalConfigChanges) { try { var oldHistorical = await historicalConfigChangesRepository.FindById(historicalConfigChanges.Id) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); var result = await historicalConfigChangesRepository.Update(historicalConfigChanges); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldHistorical, result); return result; } catch (Exception ex) { _logger.LogError("Exception updating historicalConfigChanges {changes} exception:{e} ", historicalConfigChanges.ToJson(), ex); return null; } } /// /// Asynchronously logs a change to a display configuration, recording the user who made the change, /// the configuration type, the previous value, and the new value. Logs an error if the insertion fails, /// or a debug message if it succeeds. /// /// The username of the user who made the configuration change. /// The type of configuration that was changed. /// The new configuration value after the change. /// The previous configuration value before the change. public async Task LogConfigChanged(string user, DisplayConfigEnums.ConfigTypes configType, string newConfig, string oldConfig) { HistoricalConfigChanges historicalConfigChanges = new() { ConfigType = configType, Time = DateTime.Now, Username = user, OldConfig = oldConfig, NewConfig = newConfig }; var result = await InsertOne(historicalConfigChanges); if (result == null) _logger.LogError("Error logging config changes. newConfig: {newConfig}, oldConfig: {oldConfig}", historicalConfigChanges.NewConfig, historicalConfigChanges.OldConfig); else _logger.LogDebug("Config changes logged. newConfig: {newConfig}, oldConfig: {oldConfig}", historicalConfigChanges.NewConfig, historicalConfigChanges.OldConfig); } }