using adas_core.Domain.Enums;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.Masters;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Models.Responses;
using MongoDB.Bson;

namespace adas_core.Application.Services.Interfaces;

public interface IPointOfCareService
{
    /// <summary>
    /// Asynchronously deletes the entity identified by the specified identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the entity to delete.</param>
    /// <returns>A task that represents the asynchronous delete operation.</returns>
    Task Delete(ObjectId id);

    /// <summary>
    /// Updates an existing point of care record with the provided information.
    /// </summary>
    /// <param name="pointOfCare">The point of care entity containing the updated data.</param>
    /// <returns>A task representing the asynchronous operation, containing the updated point of care, or null if no matching record was found.</returns>
    Task<PointOfCare?> Update(PointOfCare pointOfCare);

    /// <summary>
    /// Asynchronously updates an existing unit identified by the specified identifier with the provided unit data.
    /// </summary>
    /// <param name="id">The unique identifier of the unit to update.</param>
    /// <param name="unit">The unit data to apply to the existing record.</param>
    Task UpdateUnit(ObjectId id, Unit unit);
    /// <summary>
    /// Retrieves all PointOfCare records asynchronously.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of all PointOfCare entries.</returns>
    Task<List<PointOfCare>> GetAll();

    /// <summary>
    /// Asynchronously retrieves all PointOfCare configurations.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of all <see cref="PointOfCare"/> configurations.</returns>
    Task<List<PointOfCare>> GetAllConfigs();
    /// <summary>
    /// Asynchronously retrieves all point-of-care location information.
    /// </summary>
    /// <returns>A task representing the asynchronous operation, containing a list of all <see cref="PointOfCare"/> locations.</returns>
    Task<List<PointOfCare>> GetAllLocationInfo();

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

    /// <summary>
    /// Asynchronously retrieves a <see cref="PointOfCare"/> entity by its unique identifier, returning null if no matching record is found.
    /// </summary>
    /// <param name="id">The unique identifier of the <see cref="PointOfCare"/> to look up.</param>
    /// <returns>A task that represents the asynchronous lookup operation. The task result contains the matching <see cref="PointOfCare"/> if found, or null when no entity with the specified identifier exists.</returns>
    Task<PointOfCare?> FindById(ObjectId id);
    /// <summary>
    /// Retrieves a <see cref="PointOfCare"/> entity by its identifier, including all of its associated configuration data.
    /// </summary>
    /// <param name="id">The <see cref="ObjectId"/> of the <see cref="PointOfCare"/> to locate.</param>
    /// <returns>A task that yields the matching <see cref="PointOfCare"/> with its full configuration, or <c>null</c> if no entity is found for the supplied identifier.</returns>
    Task<PointOfCare?> FindByIdAllConfig(ObjectId id);

    /// <summary>
    /// Asynchronously retrieves all PointOfCare records associated with the specified unit identifier.
    /// </summary>
    /// <param name="unit">The unique identifier of the unit whose PointOfCare records should be retrieved.</param>
    /// <returns>A task that returns a collection of PointOfCare records for the specified unit, or <c>null</c> if no records are found.</returns>
    Task<IEnumerable<PointOfCare>?> FindAllByUnitId(ObjectId unit);

    /// <summary>
    /// Asynchronously retrieves the collection of Points of Care associated with the specified room.
    /// </summary>
    /// <param name="room">The room identifier used to look up the associated Points of Care.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains an enumerable of Points of Care found for the given room, or <c>null</c> if no matching results are found.</returns>
    Task<IEnumerable<PointOfCare>?> FindByRoom(string room);

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

    /// <summary>
    /// Retrieves all points of care associated with the specified unit identifiers.
    /// </summary>
    /// <param name="unitIds">The list of unit identifiers used to look up the associated points of care.</param>
    /// <returns>A task that represents the asynchronous operation, containing the list of points of care matching the provided unit identifiers.</returns>
    Task<List<PointOfCare>> FindAllByUnitIds(List<ObjectId> unitIds);

    /// <summary>
    /// Retrieves the information of a point of care by its identifier, optionally localized and enriched with patient data.
    /// Returns <c>null</c> when no point of care matches the specified identifier.
    /// </summary>
    /// <param name="id">The identifier of the point of care to retrieve.</param>
    /// <param name="locale">Optional locale used to localize the retrieved point of care information; when <c>null</c>, the default locale is used.</param>
    /// <param name="fillPatientData">When <c>true</c>, associated patient data is included in the result; when <c>false</c>, only the point of care information is returned.</param>
    /// <param name="ct">Token to cancel the asynchronous operation.</param>
    /// <returns>A task that yields the <see cref="PointOfCare"/> corresponding to the given identifier, or <c>null</c> if it is not found.</returns>
    Task<PointOfCare?> GetInfo(ObjectId id, LocaleEnum? locale = null, bool fillPatientData = true, CancellationToken ct = default);

    /// <summary>
    /// Inserts a new <see cref="PointOfCare"/> record into the system.
    /// </summary>
    /// <param name="pointOfCare">The <see cref="PointOfCare"/> entity to be inserted.</param>
    /// <returns>A <see cref="Task{PointOfCare}"/> containing the inserted <see cref="PointOfCare"/>, or <c>null</c> if the insertion was not performed.</returns>
    Task<PointOfCare?> InsertPointOfCare(PointOfCare pointOfCare);
    /// <summary>
    /// Retrieves the Point of Care associated with the specified patient identifier.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose Point of Care is being looked up.</param>
    /// <returns>A task that yields the <see cref="PointOfCare"/> associated with the patient, or <c>null</c> if no Point of Care is found for the given patient identifier.</returns>
    Task<PointOfCare?> FindPoCByPatientId(ObjectId patientId);

    /// <summary>
    /// Asynchronously sets the Point of Care status for the entity identified by the specified identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the entity whose Point of Care status will be updated.</param>
    /// <param name="status">The Point of Care status to assign to the entity.</param>
    /// <returns>A task that represents the asynchronous status update operation.</returns>
    Task SetPointOfCareStatus(ObjectId id, StatusEnum.PointOfCare status);

    /// <summary>
    /// Retrieves the points of care associated with the specified unit and point-of-care status, optionally excluding virtual ones.
    /// </summary>
    /// <param name="unitId">The identifier of the unit whose points of care are queried.</param>
    /// <param name="poc">The point-of-care status used to filter the results.</param>
    /// <param name="excludeVirtual">When <c>true</c>, virtual points of care are excluded from the results; otherwise, they are included.</param>
    /// <returns>A task that returns the matching collection of <see cref="PointOfCare"/> entries.</returns>
    Task<IEnumerable<PointOfCare>> FindByUnitAndStatus(ObjectId unitId, StatusEnum.PointOfCare poc,
            bool excludeVirtual = false);

    /// <summary>
    /// Checks the next admission for the specified patient location.
    /// </summary>
    /// <param name="patientLocation">The optional identifier of the patient location to check.</param>
    void CheckNextAdmission(ObjectId? patientLocation);
    /// <summary>
    /// Retrieves a <see cref="PointOfCare"/> associated with the specified bed and unit identifier, returning <c>null</c> when no matching record is found.
    /// </summary>
    /// <param name="bed">The bed identifier used to locate the point of care.</param>
    /// <param name="unitId">The MongoDB <see cref="ObjectId"/> of the unit the point of care belongs to.</param>
    /// <returns>A <see cref="Task{T}"/> that resolves to the matching <see cref="PointOfCare"/> or <c>null</c> if no record matches the supplied bed and unit.</returns>
    Task<PointOfCare?> FindByBedAndUnitId(string? bed, ObjectId? unitId);
    /// <summary>
    /// Updates the relay configuration associated with the specified point-of-care device.
    /// </summary>
    /// <param name="poc">The point-of-care device whose relay configuration should be updated.</param>
    Task UpdateRelayConfig(PointOfCare poc);
    /// <summary>
    /// Asynchronously retrieves the Point of Care (PoC) associated with the specified patient number.
    /// Returns <c>null</c> if no matching Point of Care is found for the given patient number.
    /// </summary>
    /// <param name="patientNumber">The unique patient number used to look up the associated Point of Care.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="PointOfCare"/> if found, or <c>null</c> if no match exists.</returns>
    Task<PointOfCare?> FindPoCByPatientNumber(string patientNumber);

    /// <summary>
    /// Asynchronously counts the number of Points of Contact (PoCs) associated with the specified unit identifier.
    /// </summary>
    /// <param name="unitId">The unique identifier of the unit whose PoCs should be counted.</param>
    /// <returns>A task that represents the asynchronous operation, containing the total number of PoCs linked to the given unit.</returns>
    Task<long> CountPoCsByUnitId(ObjectId unitId);
    /// <summary>
    /// Asynchronously retrieves the total number of virtual Proofs of Concept (PoCs) associated with the specified unit.
    /// </summary>
    /// <param name="unitId">The unique identifier of the unit whose virtual PoCs should be counted.</param>
    /// <returns>A <see cref="Task{Int64}"/> that represents the asynchronous operation, containing the count of virtual PoCs for the given unit.</returns>
    Task<long> CountVirtualPoCsByUnitId(ObjectId unitId);
    /// <summary>
    /// Retrieves a paginated collection of Points of Care based on the provided filter.
    /// </summary>
    /// <param name="filter">The pagination parameters used to control page size and page number.</param>
    /// <returns>A task that represents the asynchronous operation, containing the paginated response of Points of Care.</returns>
    Task<PaginationResponse<PointOfCare>> GetPaginatedPoCs(PaginationFilter filter);
    /// <summary>
    /// Deletes all PoCs associated with the specified unit identifier.
    /// </summary>
    /// <param name="unitId">The unique identifier of the unit whose PoCs should be removed.</param>
    Task DeletePoCsByUnitId(ObjectId unitId);
    /// <summary>
    /// Asynchronously retrieves the set of all camera identifiers that are currently in use.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a HashSet of ObjectId values representing the cameras currently in use.</returns>
    Task<HashSet<ObjectId>> FindAllIdCamerasInUse();
    /// <summary>
    /// Asynchronously retrieves the set of all ID relays that are currently in use.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a <see cref="HashSet{ObjectId}"/> of the ID relays currently in use.</returns>
    Task<HashSet<ObjectId>> FindAllIdRelaysInUse();
    /// <summary>
    /// Asynchronously retrieves the set of all ID beacons currently in use.
    /// </summary>
    /// <returns>A task containing a <see cref="HashSet{ObjectId}"/> of the ID beacons that are active or in use.</returns>
    Task<HashSet<ObjectId>> FindAllIdBeaconsInUse();
    /// <summary>
    /// Retrieves all Point of Care entries associated with the specified unit, including their related devices.
    /// </summary>
    /// <param name="unitId">The unique identifier of the unit whose Point of Care entries should be retrieved.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a collection of Point of Care entries with their devices, or <c>null</c> if no entries are found for the given unit.</returns>
    Task<IEnumerable<PointOfCare>?> FindAllByUnitIdWithDevices(ObjectId unitId);
}