using adas_core.Domain.Models;
using adas_core.Domain.Models.MongoModels;
using MongoDB.Bson;
using MongoDB.Driver;

namespace adas_core.Application.Repositories.Interfaces;

public interface IAppointmentRepository : IMongoRepository<PatientAppointment>
{
    /// <summary>
    /// Asynchronously retrieves the list of patient appointments associated with the specified patient identifier.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose appointments are being retrieved.</param>
    /// <returns>A task that represents the asynchronous operation, containing a list of <see cref="PatientAppointment"/> objects for the specified patient.</returns>
    Task<List<PatientAppointment>> GetByPatient(ObjectId patientId);

    /// <summary>
    /// Asynchronously inserts a single patient appointment record into the data store.
    /// </summary>
    /// <param name="appointment">The patient appointment entity to be inserted.</param>
    new Task InsertOneAsync(PatientAppointment appointment);
    /// <summary>
    /// Updates an existing patient appointment asynchronously.
    /// </summary>
    /// <param name="appointment">The patient appointment containing the updated information.</param>
    Task Update(PatientAppointment appointment);
    /// <summary>
    /// Updates the <see cref="ObjectId"/> field identified by <paramref name="nameId"/> across many records, replacing the existing value <paramref name="oldId"/> with the new value <paramref name="id"/>.
    /// </summary>
    /// <param name="nameId">The name of the field that contains the <see cref="ObjectId"/> to update.</param>
    /// <param name="id">The new <see cref="ObjectId"/> value to assign to matching records.</param>
    /// <param name="oldId">The current <see cref="ObjectId"/> value to be replaced.</param>
    Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId);
    /// <summary>
    /// Asynchronously deletes the entity identified by the specified identifier.
    /// </summary>
    /// <param name="id">The ObjectId of the entity to delete.</param>
    new Task DeleteAsync(ObjectId id);
    /// <summary>
    /// Asynchronously retrieves a cursor of <see cref="PatientAppointment"/> records associated with the specified patient identifier.
    /// </summary>
    /// <param name="patientId">The unique <see cref="ObjectId"/> of the patient whose appointments are being queried.</param>
    /// <returns>A <see cref="Task{IAsyncCursor{PatientAppointment}}"/> that yields the matching patient appointments; the cursor may be empty if no appointments are found for the given patient.</returns>
    Task<IAsyncCursor<PatientAppointment>> FindByPatientIdAsync(ObjectId patientId);
    /// <summary>
    /// Asynchronously deletes records associated with the specified patient identifier.
    /// </summary>
    /// <param name="patientId">The unique ObjectId of the patient whose related records should be removed.</param>
    Task DeleteByPatientId(ObjectId patientId);
    /// <summary>
    /// Asynchronously retrieves a <see cref="PatientAppointment"/> matching the specified patient identifier and visit number.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose appointment should be located.</param>
    /// <param name="visitNumber">The visit number used to identify the specific appointment for the patient.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the matching <see cref="PatientAppointment"/> if found; otherwise, <c>null</c>.</returns>
    Task<PatientAppointment?> FindByPatientAndVisitNumber(ObjectId patientId, string visitNumber);
    /// <summary>
    /// Asynchronously retrieves a patient appointment matching the specified patient identifier and appointment reason.
    /// Returns <c>null</c> when no matching appointment is found.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose appointment should be located.</param>
    /// <param name="appointmentReason">The appointment reason used to filter the lookup, or <c>null</c> to match any reason.</param>
    /// <returns>A <see cref="Task{PatientAppointment}"/> that resolves to the matching <see cref="PatientAppointment"/>, or <c>null</c> if none exists.</returns>
    Task<PatientAppointment?> FindByPatientAndReason(ObjectId patientId, string? appointmentReason);
    /// <summary>
    /// Retrieves a list of patient appointments associated with the specified location.
    /// </summary>
    /// <param name="location">The patient location used to filter and retrieve matching appointments.</param>
    /// <returns>A task that represents the asynchronous operation, containing a list of <see cref="PatientAppointment"/> entries for the given location.</returns>
    Task<List<PatientAppointment>> FindByLocation(PatientLocation location);
    /// <summary>
    /// Asynchronously retrieves the list of patient appointments associated with the specified point of care.
    /// </summary>
    /// <param name="poc">The point of care used to filter the patient appointments.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of patient appointments for the given point of care.</returns>
    Task<List<PatientAppointment>> FindByPoC(PointOfCare poc);
}