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

namespace adas_core.Application.Repositories.Interfaces;

public interface IPumpObservationRepository
{
    /// <summary>
    /// Asynchronously inserts a pump observation into the underlying data store.
    /// </summary>
    /// <param name="obs">The pump observation entity to persist.</param>
    Task InsertAsync(PumpObservation obs);
    /// <summary>
    /// Asynchronously inserts a collection of pump observations into the underlying data store.
    /// </summary>
    /// <param name="observations">The collection of <see cref="PumpObservation"/> records to be persisted.</param>
    Task InsertManyAsync(IEnumerable<PumpObservation> observations);

    /// <summary>
    /// Asynchronously retrieves pump observations associated with the specified device identifier, optionally filtered by a time range and limited in count.
    /// </summary>
    /// <param name="deviceId">The unique identifier of the device whose pump observations are being queried.</param>
    /// <param name="from">Optional inclusive lower bound for the observation timestamp; when null, no lower bound is applied.</param>
    /// <param name="to">Optional inclusive upper bound for the observation timestamp; when null, no upper bound is applied.</param>
    /// <param name="limit">Optional maximum number of observations to return; when null, all matching observations are returned.</param>
    /// <returns>A task that represents the asynchronous operation, yielding an enumerable collection of <see cref="PumpObservation"/> instances matching the criteria.</returns>
    Task<IEnumerable<PumpObservation>> FindByDeviceIdAsync(
            string deviceId,
            DateTime? from = null,
            DateTime? to = null,
            int? limit = null);

    /// <summary>
    /// Asynchronously retrieves the most recent <see cref="PumpObservation"/> associated with the specified device identifier.
    /// </summary>
    /// <param name="deviceId">The unique identifier of the device whose last observation is being queried.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the last <see cref="PumpObservation"/> for the device, or <c>null</c> if no observation exists for the given device.</returns>
    Task<PumpObservation?> FindLastByDeviceIdAsync(string deviceId);
    /// <summary>
    /// Asynchronously retrieves the most recent observation time for all patients, returning a mapping of patient identifiers to their last observation timestamps.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a dictionary where each key is a patient <see cref="ObjectId"/> and the associated value is the <see cref="DateTime"/> of that patient's last observation.</returns>
    Task<Dictionary<ObjectId, DateTime>> FindAllLastPatientObservationTimeAsync();

    /// <summary>
    /// Asynchronously retrieves the pump observations associated with the specified patient identifier.
    /// </summary>
    /// <param name="patientId">The identifier of the patient whose pump observations are being queried. May be <see langword="null"/>.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the collection of <see cref="PumpObservation"/> items found for the patient, or an empty collection if no observations are found.</returns>
    Task<IEnumerable<PumpObservation>> FindByPatientId(ObjectId? patientId);

    /// <summary>
    /// Retrieves the most recent aggregated pump observations for a specified patient, ordered from newest to oldest.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose observations are being queried.</param>
    /// <param name="num">The maximum number of observations to return. Defaults to 100.</param>
    /// <returns>A task that represents the asynchronous operation, containing a list of the patient's most recent <see cref="PumpObservation"/> entries.</returns>
    Task<List<PumpObservation>> AggregatedPatientLastObservations(ObjectId patientId, int num = 100);
    /// <summary>
    /// Deletes all records associated with the specified patient identifier. If the patient identifier is null, no deletion is performed.
    /// </summary>
    /// <param name="patientId">The optional patient identifier whose related records should be removed.</param>
    Task DeleteByPatientId(ObjectId? patientId);
    /// <summary>
    /// Asynchronously deletes records older than the specified number of days, optionally filtered by name, and returns the number of items removed.
    /// </summary>
    /// <param name="days">The age threshold in days; only records older than this value will be deleted.</param>
    /// <param name="name">An optional name used to filter which records are targeted for deletion. If null, deletion applies to all records regardless of name.</param>
    /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous operation, containing the total count of deleted records.</returns>
    Task<long> DeleteOlderThanDaysAsync(int days, string? name = null);
    /// <summary>
    /// Asynchronously deletes items, retaining only the most recent <paramref name="maxCount"/> entries, and returns the number of items that were removed.
    /// </summary>
    /// <param name="maxCount">The maximum number of most recent items to keep after the deletion.</param>
    /// <returns>A task representing the asynchronous operation, containing the count of items that were deleted.</returns>
    Task<long> DeleteKeepLastNAsync(int maxCount);
    
    /// <summary>
    /// Asynchronously updates the ObjectId value of the specified field for multiple records, replacing the existing value (optionally matched by <paramref name="oldId"/>) with <paramref name="newId"/>.
    /// </summary>
    /// <param name="fieldName">The name of the field whose ObjectId value will be updated.</param>
    /// <param name="newId">The new ObjectId value to assign to the field.</param>
    /// <param name="oldId">The optional current ObjectId value used as a filter; when <see langword="null"/>, the update is applied without filtering by the previous value.</param>
    /// <returns>A <see cref="Task{T}"/> that represents the asynchronous operation, containing the number of records updated.</returns>
    Task<long> UpdateManyObjectIdByFieldAsync(string fieldName, ObjectId newId, ObjectId? oldId);
}