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);
}
}