using adas_core.Application.Exceptions; using adas_core.Application.Repositories.Interfaces; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.Filter; using adas_core.Domain.Models.MongoModels; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; using Newtonsoft.Json; using Serilog; using System.Text.RegularExpressions; namespace adas_core.Infrastructure.Repositories; /// /// Repository for managing camera entities in the MongoDB database. This repository provides methods to create, retrieve, update, and search for cameras based on various criteria. /// It also includes error handling and logging for debugging purposes. /// public class CameraRepository : MongoRepository, ICameraRepository { private readonly ApiSettings _apiSettings; /// /// Initializes a new instance of the CameraRepository class with the specified MongoDB database and API settings. /// The constructor sets up the repository to interact with the "Cameras" collection in the database and allows for configuration through the provided API settings. /// /// The MongoDB database instance. /// The API settings containing configuration for the repository. public CameraRepository(IMongoDatabase database, IOptions apiSettings) : base(database) { _apiSettings = apiSettings.Value; } /// /// Gets the name of the MongoDB collection that this repository interacts with. In this case, it returns the collection name for cameras as specified in the API settings. /// /// The name of the MongoDB collection for cameras. public override string GetCollectionName() { return _apiSettings.Cameras; } /// /// Retrieves a camera entity from the MongoDB database based on its unique identifier. The method takes an ObjectId as a parameter and returns the corresponding Camera object if found, or null if no matching camera is found. /// It also includes error handling to log any exceptions that occur during the retrieval process. /// /// The unique identifier of the camera to retrieve. /// The Camera object if found; otherwise, null. public async Task GetById(ObjectId cameraId) { try { var filter = Builders.Filter.Eq(x => x.Id, cameraId); var result = await Collection.FindAsync(filter, null); return result.FirstOrDefault(); } catch (Exception e) { Log.Error("Exception trying to get relay by id: {id}. Exception {e}", cameraId, e); return null; } } /// /// Retrieves a camera entity from the MongoDB database based on its name. The method takes a string parameter representing the name of the camera and returns the corresponding Camera object if found, or null if no matching camera is found. /// /// The name of the camera to retrieve. /// The Camera object if found; otherwise, null. public async Task GetByName(string name) { var filterBuilder = Builders.Filter; var filter = filterBuilder.Eq(r => r.Name, name); return await Collection.Find(filter).FirstOrDefaultAsync(); } /// /// Retrieves a list of camera entities from the MongoDB database based on a list of unique identifiers. /// The method takes a list of ObjectId values representing the camera IDs and returns a list of Camera objects that match any of the provided IDs. /// /// The list of camera IDs to retrieve. /// A list of Camera objects that match the provided IDs. public List GetCameraInList(List configurationRelayList) { var filterBuilder = Builders.Filter; var filter = filterBuilder.And( filterBuilder.In(r => r.Id, configurationRelayList)); return Collection.Find(filter).ToList(); } /// /// Retrieves a paginated list of camera entities from the MongoDB database based on the provided pagination filter. /// The method takes a PaginationFilter object as a parameter, which contains information about the page number, page size, and any additional filtering criteria. /// /// The pagination filter containing page number, page size, and any additional filtering criteria. /// A paginated list of Camera objects. /// Thrown when the provided filter is invalid or contains invalid data. public IFindFluent GetPaginatedCameras(PaginationFilter filter) { var filterBuilder = Builders.Filter; var sort = Builders.Sort.Ascending("name"); var filters = new List>(); if (filter.FilteredRequest == null) return CreateFindFluent(filters, sort); if (!string.IsNullOrWhiteSpace(filter.FilteredRequest.Text)) { var textFilter = filter.FilteredRequest.Text; if (textFilter.Length > 100) throw new BadRequestException("Text filter too long"); var safeInput = Regex.Escape(textFilter); filters.Add( filterBuilder.Regex( p => p.Name, new BsonRegularExpression(safeInput, "i") ) ); } return CreateFindFluent(filters, sort); } /// /// Inserts a new camera entity into the MongoDB database. The method takes a Camera object as a parameter and attempts to insert it into the collection. /// /// The Camera object to insert into the database. /// The inserted Camera object if successful; otherwise, null. public async Task InsertOneCamera(Camera camera) { try { await Collection.InsertOneAsync(camera); return await GetById(camera.Id); } catch (Exception ex) { Log.Error("Error inserting camera: {camera}. Exception: {ex}", JsonConvert.SerializeObject(camera, Formatting.Indented), ex); return null; } } /// /// Updates an existing camera entity in the MongoDB database based on its unique identifier. The method takes an ObjectId representing the camera ID and a Camera object containing the updated information. /// /// The unique identifier of the camera to update. /// The Camera object containing the updated information. /// The updated Camera object if successful; otherwise, null. public async Task UpdateCameraAsync(ObjectId objectId, Camera camera) { var filter = Builders.Filter.Eq("_id", objectId); var update = Builders.Update .Set(c => c.Streams, camera.Streams) .Set(c => c.Name, camera.Name) .Set(c => c.Username, camera.Username) .Set(c => c.Password, camera.Password) .Set(c => c.Driver, camera.Driver) .Set(c => c.Ip, camera.Ip) .Set(c => c.Streams, camera.Streams) .Set(c => c.Ptz, camera.Ptz); return await Collection.FindOneAndUpdateAsync(filter, update, new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After }); } /// /// Searches for camera entities in the MongoDB database based on a text string that matches the camera's name. /// The method takes a string parameter representing the text to search for and returns a list of Camera objects whose names match the search criteria. /// /// The text string to search for in the camera names. /// A list of Camera objects whose names match the search criteria. /// Thrown when the search text is too long. public async Task> GetSearchByNameCameras(string textToSearch) { if (string.IsNullOrWhiteSpace(textToSearch)) return []; if (textToSearch.Length > 100) throw new BadRequestException("Search text too long"); var safeInput = Regex.Escape(textToSearch); var filter = Builders.Filter.Regex( c => c.Name, new BsonRegularExpression(safeInput, "i") ); return await Collection.Find(filter).ToListAsync(); } /// /// Creates an IFindFluent object for querying the MongoDB collection based on a list of filter definitions and a sort definition. /// /// A list of filter definitions to apply to the query. /// A sort definition to apply to the query results. /// An IFindFluent object for further query customization or execution. private IFindFluent CreateFindFluent(List> filters, SortDefinition sort) { var combinedFilter = filters.Any() ? Builders.Filter.And(filters) : Builders.Filter.Empty; return Collection.Find(combinedFilter).Sort(sort); } }