using adas_core.Domain.Models;
using adas_core.Domain.Models.DTO;
using adas_core.Domain.Models.Masters;
using adas_core.Domain.Models.MongoModels;
using MongoDB.Bson;

namespace adas_core.Application.Repositories.Interfaces;

public interface IDischargeRepository : IMongoRepository<Discharge>
{
    /// <summary>
    /// Deletes the entity identified by the specified identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the entity to delete.</param>
    Task Delete(ObjectId id);

    /// <summary>
    /// Asynchronously updates an existing discharge record.
    /// </summary>
    /// <param name="discharge">The discharge entity containing the updated information to be persisted.</param>
    Task Update(Discharge discharge);

    /// <summary>
    /// Asynchronously updates the unit associated with the specified object identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the object whose unit will be updated.</param>
    /// <param name="unit">The new unit value to assign to the object.</param>
    Task UpdateUnit(ObjectId id, string unit);

    /// <summary>
    /// Updates an existing patient record identified by the specified identifier with the provided patient data.
    /// </summary>
    /// <param name="id">The unique identifier of the patient to update.</param>
    /// <param name="patient">The patient object containing the updated information to be applied to the existing record.</param>
    Task UpdatePatient(ObjectId id, Patient patient);

    /// <summary>
    /// Asynchronously retrieves all discharge records.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a collection of all <see cref="Discharge"/> entities.</returns>
    Task<IEnumerable<Discharge>> FindAll();

    /// <summary>
    /// Retrieves a <see cref="Discharge"/> record by its unique identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the discharge record to find.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="Discharge"/> if a matching record is found; otherwise, <c>null</c>.</returns>
    Task<Discharge?> FindById(ObjectId id);

    /// <summary>
    /// Asynchronously retrieves a collection of <see cref="Discharge"/> records associated with the specified unit, or <see langword="null"/> if no matching records are found.
    /// </summary>
    /// <param name="unit">The unit identifier used to filter the discharge records.</param>
    /// <returns>A task that represents the asynchronous operation. The result is an <see cref="IEnumerable{T}"/> of <see cref="Discharge"/> containing the matching records, or <see langword="null"/> when no records are found.</returns>
    Task<IEnumerable<Discharge>?> FindByUnit(string unit);

    /// <summary>
    /// Asynchronously counts the number of records associated with the specified unit identifier.
    /// </summary>
    /// <param name="unitId">The ObjectId of the unit whose associated records will be counted.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the count of records for the specified unit.</returns>
    Task<long> CountByUnitId(ObjectId unitId);

    /// <summary>
    /// Asynchronously retrieves the collection of discharge records associated with the specified destination.
    /// </summary>
    /// <param name="destination">The destination identifier used to look up matching discharge records.</param>
    /// <returns>A task that yields an <see cref="IEnumerable{Discharge}"/> of matching discharge records, or <c>null</c> if no records are found for the given destination.</returns>
    Task<IEnumerable<Discharge>?> FindByDestination(string destination);

    /// <summary>
    /// Asynchronously retrieves a collection of discharges associated with the specified service.
    /// Returns null when no matching discharges are found for the given service.
    /// </summary>
    /// <param name="service">The service identifier used to look up matching discharge records.</param>
    /// <returns>A task that represents the asynchronous operation. The result is an <see cref="IEnumerable{T}"/> of <see cref="Discharge"/> entries for the specified service, or <c>null</c> if none are found.</returns>
    Task<IEnumerable<Discharge>?> FindByService(string service);
    /// <summary>
    /// Asynchronously retrieves a collection of <see cref="Discharge"/> records associated with the specified unit identifiers.
    /// </summary>
    /// <param name="unitIds">The collection of unit identifiers used to look up the matching discharges. May be <c>null</c>.</param>
    /// <returns>A task that represents the asynchronous operation, containing a collection of <see cref="Discharge"/> objects, or <c>null</c> when no matching discharges are available.</returns>
    Task<IEnumerable<Discharge>?> GetDischargesByUnitIds(IEnumerable<ObjectId>? unitIds);


    /// <summary>
    /// Asynchronously retrieves the discharge record associated with the specified patient location, returning null if no discharge is found for that location.
    /// </summary>
    /// <param name="location">The patient location used to look up the associated discharge record.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the matching <see cref="Discharge"/> if found; otherwise, <c>null</c>.</returns>
    Task<Discharge?> GetDischargeByLocation(PatientLocation location);
    /// <summary>
    /// Retrieves the discharge record associated with the specified patient identifier, or <see langword="null"/> if no discharge exists for that patient.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose discharge record is being requested.</param>
    /// <returns>A <see cref="Task{Discharge}"/> that resolves to the matching <see cref="Discharge"/>, or <see langword="null"/> when no record is found.</returns>
    Task<Discharge?> GetByPatientId(ObjectId patientId);

    /// <summary>
    /// Asynchronously retrieves the collection of <see cref="Discharge"/> records associated with the specified point-of-care identifier.
    /// </summary>
    /// <param name="pocId">The point-of-care identifier used to look up the associated discharges.</param>
    /// <returns>A task that returns an <see cref="IEnumerable{T}"/> of <see cref="Discharge"/> records, or <see langword="null"/> if no discharges are found for the given point-of-care identifier.</returns>
    Task<IEnumerable<Discharge>?> FindByPoCId(ObjectId pocId);
    /// <summary>
    /// Retrieves the discharge associated with the specified point of care identifier.
    /// </summary>
    /// <param name="poc">The identifier of the point of care used to look up the discharge.</param>
    /// <returns>A task that returns the matching <see cref="Discharge"/> if one is found; otherwise, <c>null</c>.</returns>
    Task<Discharge?> GetDischargeByPointOfCareId(ObjectId poc);

    /// <summary>
    /// Updates the master list option for the specified units based on the provided update details and type name.
    /// </summary>
    /// <param name="unitIds">The list of unit identifiers to be updated.</param>
    /// <param name="opt">The update option master list data transfer object containing the new option details.</param>
    /// <param name="typeName">The name of the type to which the master list option applies.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a collection of updated Discharge records.</returns>
    Task<IEnumerable<Discharge>> UpdateMasterListOption(List<ObjectId> unitIds, UpdateOptionMasterListDto opt,
            string typeName);

    /// <summary>
    /// Deletes the specified master list option from the given units and returns the resulting discharges.
    /// </summary>
    /// <param name="unitIds">The identifiers of the units from which the option will be removed.</param>
    /// <param name="opt">The master list option to delete.</param>
    /// <param name="typeName">The type name associated with the option.</param>
    /// <returns>A task that represents the asynchronous operation, containing the collection of <see cref="Discharge"/> objects resulting from the deletion.</returns>
    Task<IEnumerable<Discharge>> DeleteMasterListOption(List<ObjectId> unitIds, OptionList opt, string typeName);
    /// <summary>
    /// Deletes the entity associated with the specified unit identifier.
    /// </summary>
    /// <param name="unitId">The unique identifier of the unit whose associated record should be removed.</param>
    /// <returns>A task that represents the asynchronous operation. The result is <c>true</c> if a record was deleted; otherwise, <c>false</c>.</returns>
    Task<bool> DeleteByUnitId(ObjectId unitId);
}