using adas_core.Application.Repositories.Interfaces; using adas_core.Application.Services.Interfaces; using adas_core.Domain.Models.Filter; using adas_core.Domain.Models.MongoModels; using adas_core.Domain.Models.Responses; using Microsoft.Extensions.Logging; using MongoDB.Bson; using MongoDB.Driver; namespace adas_core.Application.Services; /// /// Provides camera-related operations by coordinating the camera repository and point-of-care service, and logging diagnostic information. /// /// /// This service implements and serves as the application-layer entry point for camera functionality. /// /// public class CameraService(ILogger logger, ICameraRepository cameraRepository, IPointOfCareService pointOfCareService) : ICameraService { private ICameraRepository _cameraRepository = cameraRepository; /// /// Retrieves a camera by its associated relay identifier from the camera repository. /// Returns null when no camera is found for the specified relay identifier. /// /// The unique identifier of the relay used to look up the camera. /// A task that represents the asynchronous operation. The task result contains the matching , or null if no camera is found. /// public Task GetById(ObjectId relayId) { return _cameraRepository.GetById(relayId); } /// /// Retrieves the list of cameras associated with the specified configuration relay identifiers. /// /// The list of configuration relay identifiers used to look up the corresponding cameras. /// A containing the cameras linked to the provided configuration relay identifiers. /// public List GetCameraInList(List configurationRelayList) { return _cameraRepository.GetCameraInList(configurationRelayList); } /// /// Retrieves a paginated list of cameras, optionally filtered by whether they are currently in use, and resolves the in-use status for each returned camera using the point-of-care service. /// /// The pagination filter that controls page number, page size, and optional filtering criteria such as the in-use flag. /// A paginated response containing the requested cameras, the current page metadata, and the total document count; if no data is found, an empty paginated response is returned. /// public async Task> GetPaginatedCameras(PaginationFilter filter) { var usedCameraIds = await pointOfCareService.FindAllIdCamerasInUse(); var fluentQuery = _cameraRepository.GetPaginatedCameras(filter); if (filter.FilteredRequest?.InUse != null) { bool filterInUse = filter.FilteredRequest.InUse.Value; var filterBuilder = Builders.Filter; var idFilter = filterInUse ? filterBuilder.In(c => c.Id, usedCameraIds) : filterBuilder.Not(filterBuilder.In(c => c.Id, usedCameraIds)); fluentQuery.Filter = filterBuilder.And(fluentQuery.Filter, idFilter); } var count = await fluentQuery.CountDocumentsAsync(); var data = await fluentQuery .Skip((filter.PageNumber - 1) * filter.PageSize) .Limit(filter.PageSize) .ToListAsync(); if (data == null) return new PaginationResponse([], filter.PageNumber, filter.PageSize, count); foreach (var camera in data) { if (camera == null) continue; bool isInUse = usedCameraIds.Contains(camera.Id); // Asignación mediante reflexión para el private set camera.GetType().GetProperty(nameof(Camera.InUse)) ?.SetValue(camera, isInUse); } return new PaginationResponse(data, filter.PageNumber, filter.PageSize, count); } /// /// Inserts a new camera into the system after validating its name and ensuring no duplicate exists. /// Throws an exception if the camera name is null or if another camera with the same name already exists. /// /// The camera entity to insert. /// The inserted camera, or null if the insertion did not return a result. /// Thrown when the camera name is null. /// Thrown when a camera with the same name already exists. /// public async Task InsertCamera(Camera camera) { if (camera.Name == null) throw new Exception("Camera name cannot be null"); var cameraFound = await _cameraRepository.GetByName(camera.Name); if (cameraFound != null) throw new Exception($"Camera with name {camera.Name} already exists"); return await _cameraRepository.InsertOneCamera(camera); } /// /// Updates an existing camera identified by its unique identifier, returning the updated entity if the operation succeeds. /// /// The unique identifier of the camera to update. /// The camera data containing the updated values. /// A task that represents the asynchronous operation. The task result contains the updated , or null if no camera with the specified identifier was found. /// public async Task UpdateCameraById(ObjectId objectId, Camera camera) { return await _cameraRepository.UpdateCameraAsync(objectId, camera); } /// /// Deletes a camera identified by the specified object identifier. Returns false when the camera is not found, and logs and returns false if an error occurs during the operation. /// /// The unique identifier of the camera to delete. /// true if the camera was successfully deleted; otherwise, false. /// public async Task DeleteCamera(ObjectId objectId) { try { var cameraToDelete = await _cameraRepository.GetById(objectId); if (cameraToDelete == null) return false; await _cameraRepository.DeleteAsync(cameraToDelete.Id); return true; } catch (Exception e) { logger.LogError(e, e.Message); return false; } } /// /// Retrieves a list of cameras matching the specified search text by delegating to the camera repository. /// /// The search text used to find cameras by name. /// A task that represents the asynchronous operation, containing a list of objects that match the search criteria. /// public async Task> GetSearchByNameCameras(string textToSearch) { return await _cameraRepository.GetSearchByNameCameras(textToSearch); } }