using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.DTO;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.GroupedObservations;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Models.Pumps;
using adas_core.Domain.Models.Responses;
using MongoDB.Bson;

namespace adas_core.Application.Services.Interfaces;

public interface IConfigObservationService
{
    /// <summary>
    /// Retrieves a <see cref="ConfigObservation"/> identified by the specified coding system and code.
    /// Returns <c>null</c> when no matching configuration observation is found.
    /// </summary>
    /// <param name="codingSystem">The coding system used to identify the configuration observation (e.g., ICD, SNOMED).</param>
    /// <param name="code">The code within the given coding system that uniquely identifies the configuration observation.</param>
    /// <returns>A <see cref="ConfigObservation"/> if a match is found; otherwise, <c>null</c>.</returns>
    Task<ConfigObservation?> GetByCodeSysAndCode(string codingSystem, string code);
    /// <summary>
    /// Asynchronously retrieves a <see cref="ConfigObservation"/> identified by the given name.
    /// Returns <see langword="null"/> when no matching configuration observation is found.
    /// </summary>
    /// <param name="name">The name of the configuration observation to retrieve.</param>
    /// <returns>A <see cref="Task{TResult}"/> that yields the matching <see cref="ConfigObservation"/>, or <see langword="null"/> if no observation is found.</returns>
    Task<ConfigObservation?> Get(string name);

    /// <summary>
    /// Retrieves the <see cref="ConfigObservation"/> associated with the specified patient observation, optionally restricting the lookup to a match performed by name only.
    /// </summary>
    /// <param name="obs">The patient observation whose corresponding configuration observation is being requested.</param>
    /// <param name="onlyByName">When <c>true</c>, limits the lookup to a name-based match; otherwise, other matching criteria may be applied.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the matching <see cref="ConfigObservation"/>, or <c>null</c> if no matching observation is found.</returns>
    Task<ConfigObservation?> Get<T>(T obs, bool onlyByName = false) where T : BasePatientObservation;
    
    /// <summary>
    /// Performs retention actions for the specified patient observation and returns the resulting retention outcome.
    /// </summary>
    /// <param name="obs">The patient observation of type <typeparamref name="T"/> on which retention actions will be executed.</param>
    /// <returns>A task that represents the asynchronous retention operation. The task result contains the <see cref="ObservatitonRetentionResult"/> produced by the retention actions, or <c>null</c> when no retention result is produced.</returns>
    Task<ObservatitonRetentionResult?> RetentionActions<T>(T obs) where T : BasePatientObservation;
    /// <summary>
    /// Maps a patient observation to a corresponding target observation of the same type, optionally restricting the lookup 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 using the observation's name only; otherwise, additional matching criteria are considered. Defaults to <c>false</c>.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the mapped patient observation of type <typeparamref name="T"/>, or <c>null</c> if no matching observation is found.</returns>
    Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation;
    /// <summary>
    /// Asynchronously maps the specified <see cref="PatientTreatment"/> to a populated <see cref="PatientTreatment"/> instance, returning <see langword="null"/> when the treatment cannot be resolved.
    /// </summary>
    /// <param name="treatment">The <see cref="PatientTreatment"/> to be mapped.</param>
    /// <returns>A <see cref="Task{TResult}"/> that yields the mapped <see cref="PatientTreatment"/>, or <see langword="null"/> if no mapping result is available.</returns>
    Task<PatientTreatment?> Map(PatientTreatment treatment);

    /// <summary>
    /// Determines the status of a grouped observation field based on the provided result, value, and optional threshold range.
    /// </summary>
    /// <param name="groupedField">The grouped field associated with the observation.</param>
    /// <param name="result">The result of the grouped observation used to evaluate the status.</param>
    /// <param name="name">The name of the field or value being evaluated.</param>
    /// <param name="value">The value associated with the grouped observation.</param>
    /// <param name="min">The optional minimum threshold for the value.</param>
    /// <param name="max">The optional maximum threshold for the value.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the evaluated <see cref="StatusEnum.Type"/> for the grouped observation.</returns>
    Task<StatusEnum.Type> GroupedObservationStatus(GroupedField groupedField, GroupedObservationEnum.Result result,
            string name, object value, double? min, double? max);

    /// <summary>
    /// Retrieves all configuration observations asynchronously.
    /// </summary>
    /// <param name="ct">The cancellation token used to cancel the asynchronous operation.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a collection of <see cref="ConfigObservation"/> objects representing all available configurations.</returns>
    Task<ICollection<ConfigObservation>> GetAllConfigs(CancellationToken ct = default);
    /// <summary>
    /// Retrieves a paginated collection of <see cref="ConfigObservation"/> items based on the supplied filter criteria.
    /// </summary>
    /// <param name="filter">The pagination filter that defines the page size, page number, and query criteria used to retrieve the configuration observations.</param>
    /// <returns>A task that represents the asynchronous operation, containing a <see cref="PaginationResponse{ConfigObservation}"/> with the requested items and pagination metadata.</returns>
    Task<PaginationResponse<ConfigObservation>> GetPaginatedItems(PaginationFilter filter);
    /// <summary>
    /// Retrieves all configuration observations in a compact format.
    /// </summary>
    /// <returns>A task representing the asynchronous operation that returns a <see cref="ConfigObservationDto"/> containing the compact representation of all configuration observations.</returns>
    Task<ConfigObservationDto> GetAllCompact();
    /// <summary>
    /// Retrieves a configuration observation by its unique identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the configuration observation to retrieve.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="ConfigObservation"/> if a matching record is found, or <c>null</c> if no configuration exists for the specified id.</returns>
    Task<ConfigObservation?> GetConfigById(ObjectId id);
    /// <summary>
    /// Asynchronously retrieves a list of configuration names associated with the specified identifier.
    /// </summary>
    /// <param name="id">The identifier used to look up the associated configuration names.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of configuration names.</returns>
    Task<List<string>> GetConfigNames(string id);
    /// <summary>
    /// Asynchronously retrieves the list of available configuration names.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation, containing a list of configuration names.</returns>
    Task<List<string>> GetConfigNames();
    /// <summary>
    /// Updates an existing configuration observation and returns the updated result.
    /// </summary>
    /// <param name="configObservation">The configuration observation containing the data to update.</param>
    /// <returns>A task that resolves to the updated <see cref="ConfigObservation"/>, or <c>null</c> when no matching configuration is found.</returns>
    Task<ConfigObservation?> UpdateConfig(ConfigObservation configObservation);
    /// <summary>
    /// Asynchronously creates a new configuration based on the provided observation data.
    /// </summary>
    /// <param name="configObservation">The observation data used to create the configuration.</param>
    /// <returns>A task that represents the asynchronous operation, containing the created <see cref="ConfigObservation"/>, or <c>null</c> if the configuration could not be created.</returns>
    Task<ConfigObservation?> CreateConfig(ConfigObservation configObservation);
    /// <summary>
    /// Asynchronously removes the configuration item with the specified name.
    /// </summary>
    /// <param name="itemName">The name of the configuration item to remove.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a <see cref="ConfigObservation"/> describing the removed item, or <c>null</c> if no matching item was found.</returns>
    Task<ConfigObservation?> RemoveConfigItem(string itemName);
    /// <summary>
    /// Asynchronously removes the configuration item identified by the specified identifier and returns the resulting observation.
    /// </summary>
    /// <param name="id">The unique identifier of the configuration item to remove.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="ConfigObservation"/> describing the removed configuration item, or <c>null</c> if no matching item was found.</returns>
    Task<ConfigObservation?> RemoveConfigItem(ObjectId id);
    /// <summary>
    /// Retrieves the configuration observation items associated with the specified name.
    /// </summary>
    /// <param name="name">The name used to look up the configuration observation items.</param>
    /// <returns>A task that represents the asynchronous operation. The result contains a collection of <see cref="ConfigObservation"/> items matching the provided name, or <c>null</c> if no matching items are found.</returns>
    Task<IEnumerable<ConfigObservation>?> GetConfigObservationItem(string name);

    /// <summary>
    /// Retrieves a single configuration observation item based on the provided code, coding system, name, and original name.
    /// </summary>
    /// <param name="code">The code used to identify the configuration observation item.</param>
    /// <param name="codingSystem">The coding system associated with the code.</param>
    /// <param name="name">The name of the configuration observation item.</param>
    /// <param name="originalName">The original name of the configuration observation item.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the matching <see cref="ConfigObservation"/>, or <c>null</c> if no item is found.</returns>
    Task<ConfigObservation?> GetSingleConfigObservationItem(string? code, string? codingSystem, string? name,
            string? originalName);

    /// <summary>
    /// Asynchronously deletes a single configuration observation item from the underlying store.
    /// </summary>
    /// <param name="configObservationItem">The configuration observation item to be deleted.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the deletion was successful.</returns>
    Task<bool> DeleteSingleConfigObservationItem(ConfigObservation configObservationItem);
    /// <summary>
    /// Retrieves configuration observation items that match the specified name.
    /// </summary>
    /// <param name="name">The name used to filter the configuration observation items.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the collection of <see cref="ConfigObservation"/> items matching the specified name.</returns>
    Task<IEnumerable<ConfigObservation>> GetConfigObservationItemsByName(string name);
}