using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.Pumps;
using MongoDB.Bson;

namespace adas_core.Application.Services.Interfaces;

public interface ICalculatedObservations
{
    /// <summary>
    /// Asynchronously maps a patient observation to a corresponding target type, optionally restricting the mapping to name-based matching only.
    /// </summary>
    /// <param name="obs">The source patient observation to be mapped.</param>
    /// <param name="onlyByName">When set to <c>true</c>, the mapping is performed considering only the observation name; otherwise, additional mapping criteria are applied. Defaults to <c>false</c>.</param>
    /// <returns>A <see cref="Task{T}"/> that represents the asynchronous mapping operation. The result is the mapped observation of type <typeparamref name="T"/>, or <c>null</c> when no matching mapping is found.</returns>
    Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation;
    /// <summary>
    /// Asynchronously maps the specified <paramref name="treatment"/> to a <see cref="PatientTreatment"/> result.
    /// </summary>
    /// <param name="treatment">The patient treatment instance to map.</param>
    /// <returns>A task that represents the asynchronous mapping operation. The task result contains the mapped <see cref="PatientTreatment"/>.</returns>
    Task<PatientTreatment> Map(PatientTreatment treatment);
    /// <summary>
    /// Asynchronously maps a <see cref="PatientDiagnosis"/> to a <see cref="PatientDiagnosis"/> representation.
    /// </summary>
    /// <param name="diagnosis">The patient diagnosis to be mapped.</param>
    /// <returns>A task that represents the asynchronous mapping operation, containing the mapped <see cref="PatientDiagnosis"/>.</returns>
    Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis);

    /// <summary>
    /// Asynchronously maps the specified <see cref="PumpObservation"/> to a <see cref="PumpObservation"/> result.
    /// </summary>
    /// <param name="pumpObservation">The <see cref="PumpObservation"/> to be mapped.</param>
    /// <returns>A <see cref="Task{TResult}"/> representing the asynchronous operation, containing the mapped <see cref="PumpObservation"/>.</returns>
    Task<PumpObservation> Map(PumpObservation pumpObservation);

    /// <summary>
    /// Asynchronously calculates a medicine observation for a patient based on their active medicines.
    /// </summary>
    /// <param name="activeMedicines">The list of medicines currently active for the patient.</param>
    /// <param name="patientId">The unique identifier of the patient whose observation is being calculated.</param>
    Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId);

    /// <summary>
    /// Calculates the active bolus for the specified patient.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose active bolus is to be calculated.</param>
    Task CalculateActiveBolus(ObjectId patientId);

    /// <summary>
    /// Retrieves the active treatments associated with a specific patient by their unique identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the patient whose active treatments are being queried.</param>
    /// <returns>A task that represents the asynchronous operation, containing a collection of nullable <see cref="PatientTreatment"/> entries that represent the active treatments for the specified patient.</returns>
    Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id);

    /// <summary>
    /// Resolves time inconsistencies between the new observation and the last stored observation, returning a corrected version when applicable.
    /// </summary>
    /// <param name="newObservation">The new patient observation to validate and reconcile against the previous observation's time information.</param>
    /// <returns>A task that yields the fixed <see cref="PatientObservation"/>, or <c>null</c> when no time inconsistency is detected or no correction is required.</returns>
    Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation);
    /// <summary>
    /// Performs pre-insertion mapping on a list of patient observations, transforming or preparing the data before it is persisted.
    /// </summary>
    /// <param name="listToInsert">The list of patient observations to be pre-mapped prior to insertion.</param>
    /// <returns>A task that represents the asynchronous operation, containing the mapped list of patient observations.</returns>
    Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert);
    /// <summary>
    /// Maps the source alarm onto the specified patient observation and returns the resulting observation.
    /// </summary>
    /// <param name="obs">The patient observation to which the source alarm will be mapped.</param>
    /// <param name="alarmToInsert">The patient observation alarm to insert and map as the source alarm.</param>
    /// <returns>A task representing the asynchronous operation, containing the patient observation with the source alarm mapped.</returns>
    Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert);

    /// <summary>
    /// Sends an alarm associated with the specified patient observation, optionally classified by an alarm code.
    /// </summary>
    /// <param name="obs">The patient observation that triggered the alarm.</param>
    /// <param name="name">The name associated with the alarm.</param>
    /// <param name="code">An optional alarm code categorizing the type of alarm to send.</param>
    Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code);
}