using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.DTO;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.MongoModels;
using MongoDB.Bson;
using MongoDB.Driver;

namespace adas_core.Application.Repositories.Interfaces;

public interface IPointOfCareRepository : IMongoRepository<PointOfCare>
{
    /// <summary>
    /// Asynchronously deletes the entity identified by the specified <paramref name="id"/>.
    /// </summary>
    /// <param name="id">The <see cref="ObjectId"/> of the entity to delete.</param>
    Task Delete(ObjectId id);

    /// <summary>
    /// Asynchronously updates the specified <see cref="PointOfCare"/> entity.
    /// </summary>
    /// <param name="pointOfCare">The <see cref="PointOfCare"/> instance containing the updated data to be persisted.</param>
    Task Update(PointOfCare pointOfCare);

    /// <summary>
    /// Updates the unit identifier associated with the specified object.
    /// </summary>
    /// <param name="id">The identifier of the object whose unit will be updated.</param>
    /// <param name="unit">The unit value to apply to the object.</param>
    Task UpdateUnitId(ObjectId id, Unit unit);

    /// <summary>
    /// Updates the point of care configuration identified by the specified identifier with the provided settings.
    /// </summary>
    /// <param name="id">The unique identifier of the point of care configuration to update.</param>
    /// <param name="configuration">The new configuration values to apply to the existing point of care record.</param>
    Task UpdateConfiguration(ObjectId id, PointOfCareConfiguration configuration);

    /// <summary>
    /// Retrieves a <see cref="PointOfCare"/> by its identifier, returning <c>null</c> when no matching record is found.
    /// </summary>
    /// <param name="id">The unique identifier of the point of care to locate.</param>
    /// <returns>A task that yields the matching <see cref="PointOfCare"/>, or <c>null</c> if no record exists for the given identifier.</returns>
    Task<PointOfCare?> FindById(ObjectId id);

    /// <summary>
    /// Retrieves all <see cref="PointOfCare"/> records associated with the specified unit identifier.
    /// </summary>
    /// <param name="unit">The <see cref="ObjectId"/> of the unit whose points of care should be returned.</param>
    /// <returns>A task that yields an <see cref="IEnumerable{T}"/> of <see cref="PointOfCare"/> for the matching unit, or <c>null</c> when no results are found.</returns>
    Task<IEnumerable<PointOfCare>?> FindAllByUnitId(ObjectId unit);

    /// <summary>
    /// Asynchronously retrieves the points of care associated with the specified room.
    /// </summary>
    /// <param name="room">The room identifier used to look up the corresponding points of care.</param>
    /// <returns>A task that represents the asynchronous operation. The result is a collection of <see cref="PointOfCare"/> matching the specified room, or <see langword="null"/> if no matching points of care are found.</returns>
    Task<IEnumerable<PointOfCare>?> FindByRoom(string room);

    /// <summary>
    /// Asynchronously retrieves a list of <see cref="PointOfCare"/> entities that match the specified filter, optionally applying a projection to shape the returned fields.
    /// </summary>
    /// <param name="filter">The filter definition used to match <see cref="PointOfCare"/> entities in the data store.</param>
    /// <param name="projection">An optional projection definition that limits or shapes the fields returned in each result. If <c>null</c>, the full <see cref="PointOfCare"/> entity is returned.</param>
    /// <returns>A task that represents the asynchronous operation, containing a list of <see cref="PointOfCare"/> entities that satisfy the filter. Returns an empty list when no matching entities are found.</returns>
    Task<List<PointOfCare>> FindByFilter(FilterDefinition<PointOfCare> filter,
            ProjectionDefinition<PointOfCare>? projection = null);

    /// <summary>
    /// Retrieves the points of care associated with the specified bed, returning <c>null</c> when no matching points of care are found.
    /// </summary>
    /// <param name="bed">The bed identifier used to look up the associated points of care.</param>
    /// <returns>A task that yields an <see cref="IEnumerable{T}"/> of <see cref="PointOfCare"/> when matches exist, or <c>null</c> if none are found.</returns>
    Task<IEnumerable<PointOfCare>?> FindByBed(string bed);
    /// <summary>
    /// Asynchronously retrieves all available points of care.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result is a list of <see cref="PointOfCare"/> instances, or <c>null</c> if no points of care are available.</returns>
    Task<List<PointOfCare>?> GetAll();
    /// <summary>
    /// Retrieves all Point of Care configurations available in the system.
    /// </summary>
    /// <returns>A task containing a list of <see cref="PointOfCare"/> configurations, or <c>null</c> if no configurations are found.</returns>
    Task<List<PointOfCare>?> GetAllConfigs();

    /// <summary>
    /// Retrieves all Point of Care location information.
    /// </summary>
    /// <returns>A task that resolves to a list of <see cref="PointOfCare"/> locations, or <c>null</c> if no location data is available.</returns>
    Task<List<PointOfCare>?> GetAllLocationInfo();

    /// <summary>
    /// Retrieves the Point of Care configuration associated with the specified identifier.
    /// Returns null when no configuration exists for the given identifier.
    /// </summary>
    /// <param name="pocId">The unique identifier of the Point of Care whose configuration is being requested.</param>
    /// <returns>A task that resolves to the matching <see cref="PointOfCare"/> configuration, or null if no configuration is found.</returns>
    Task<PointOfCare?> GetPoCConfiguration(ObjectId pocId);


    /// <summary>
    /// Asynchronously retrieves the <see cref="PointOfCare"/> associated with the specified bed within the given unit, returning <see langword="null"/> if no matching record is found.
    /// </summary>
    /// <param name="bed">The bed identifier used to locate the point of care; may be <see langword="null"/>.</param>
    /// <param name="unitId">The identifier of the unit in which the bed is located.</param>
    /// <returns>A <see cref="Task{TResult}"/> that yields the matching <see cref="PointOfCare"/>, or <see langword="null"/> if none is found.</returns>
    Task<PointOfCare?> FindByBedAndUnitId(string? bed, ObjectId unitId);

    /// <summary>
    /// Retrieves the point of care associated with the specified patient location.
    /// </summary>
    /// <param name="patientLocation">The patient location used to look up the corresponding point of care.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the matching <see cref="PointOfCare"/>, or <c>null</c> if no point of care is found for the given patient location.</returns>
    Task<PointOfCare?> FindByPatientLocation(PatientLocation patientLocation);

    /// <summary>
    /// Retrieves a collection of <see cref="PointOfCare"/> entities that belong to the specified unit and match the given status.
    /// When <paramref name="excludeVirtual"/> is <c>true</c>, virtual points of care are omitted from the results.
    /// </summary>
    /// <param name="unitId">The identifier of the unit whose points of care are being queried.</param>
    /// <param name="status">The point-of-care status used to filter the results.</param>
    /// <param name="excludeVirtual">When set to <c>true</c>, virtual points of care are excluded from the returned collection.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains an <see cref="IEnumerable{PointOfCare}"/> of points of care matching the specified unit and status.</returns>
    Task<IEnumerable<PointOfCare>> FindByUnitAndStatus(ObjectId unitId, StatusEnum.PointOfCare status,
            bool excludeVirtual = false);

    /// <summary>
    /// Updates the relay configuration associated with the specified point of contact identifier.
    /// </summary>
    /// <param name="pocId">The unique identifier of the point of contact whose relay configuration is being updated.</param>
    /// <param name="relayConfig">The collection of relay entries to apply to the configuration.</param>
    Task UpdateRelayConfig(ObjectId pocId, List<Relay> relayConfig);
    /// <summary>
    /// Updates the relay configuration for the specified point of configuration (POC) using the provided list of relay configuration identifiers.
    /// </summary>
    /// <param name="pocId">The unique identifier of the point of configuration whose relay configuration will be updated.</param>
    /// <param name="relayConfig">The list of relay configuration identifiers to apply to the specified POC.</param>
    Task UpdateRelayConfig(ObjectId pocId, List<ObjectId> relayConfig);

    /// <summary>
    /// Retrieves a paginated, fluent queryable collection of Points of Care (PoCs) based on the provided filter criteria.
    /// </summary>
    /// <param name="filter">The pagination filter that defines paging parameters such as page number and page size.</param>
    /// <returns>An <see cref="IFindFluent{PointOfCare, PointOfCare}"/> representing the paginated query against the PoCs collection.</returns>
    IFindFluent<PointOfCare, PointOfCare> GetPaginatedPoCs(PaginationFilter filter);
    /// <summary>
    /// Asynchronously counts the number of entities associated with the specified unit identifier.
    /// </summary>
    /// <param name="unitId">The identifier of the unit used to filter the entities to be counted.</param>
    /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous operation, containing the total count of matching entities.</returns>
    Task<long> CountByUnitId(ObjectId unitId);
    /// <summary>
    /// Asynchronously counts the number of virtuals associated with the specified unit.
    /// </summary>
    /// <param name="unitId">The identifier of the unit whose virtuals will be counted.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the count of virtuals for the given unit.</returns>
    Task<long> CountVirtualsByUnitId(ObjectId unitId);
    /// <summary>
    /// Deletes multiple records associated with the specified unit identifier asynchronously.
    /// </summary>
    /// <param name="unitId">The unique identifier of the unit whose related records should be deleted.</param>
    /// <returns>A task that represents the asynchronous operation, containing a boolean value indicating whether the deletion was successful.</returns>
    Task<bool> DeleteManyByUnitId(ObjectId unitId);
    /// <summary>
    /// Retrieves a <see cref="PointOfCare"/> entity by its identifier, including all associated configuration data.
    /// Returns <see langword="null"/> when no matching entity is found.
    /// </summary>
    /// <param name="id">The unique identifier of the point of care to retrieve.</param>
    /// <returns>A task that resolves to the matching <see cref="PointOfCare"/> with all configuration, or <see langword="null"/> if not found.</returns>
    Task<PointOfCare?> FindByIdAllConfig(ObjectId id);
    /// <summary>
    /// Asynchronously retrieves the set of camera identifiers that are currently in use.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation, containing a hash set of <see cref="ObjectId"/> values for all cameras in use.</returns>
    Task<HashSet<ObjectId>> FindAllIdCamerasInUse();
    /// <summary>
    /// Asynchronously retrieves all ID relays that are currently in use, returning them as a hash set for efficient lookup.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a hash set of the <see cref="ObjectId"/> values of all ID relays currently in use.</returns>
    Task<HashSet<ObjectId>> FindAllIdRelaysInUse();
    /// <summary>
    /// Asynchronously retrieves the set of all ID beacons that are currently in use.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a <see cref="HashSet{ObjectId}"/> with the identifiers of all ID beacons currently in use.</returns>
    Task<HashSet<ObjectId>> FindAllIdBeaconsInUse();
    /// <summary>
    /// Retrieves all points of care associated with the specified unit identifier, including their related devices.
    /// </summary>
    /// <param name="unitId">The unique identifier of the unit whose points of care and associated devices are to be retrieved.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains an enumerable collection of points of care with their associated devices, or <c>null</c> if no points of care are found for the specified unit.</returns>
    Task<IEnumerable<PointOfCare>?> FindAllByUnitIdWithDevices(ObjectId unitId);
}