using adas_core.Domain.Models;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.Responses;
using MongoDB.Bson;

namespace adas_core.Application.Services.Interfaces;

public interface IMedicineService
{
    /// <summary>
    /// Asynchronously retrieves a <see cref="Medicine"/> entity by its unique code identifier.
    /// Returns <c>null</c> when no matching medicine is found.
    /// </summary>
    /// <param name="code">The unique code used to look up the medicine.</param>
    /// <returns>A task that represents the asynchronous operation, containing the matching <see cref="Medicine"/> or <c>null</c> if not found.</returns>
    Task<Medicine?> GetByCode(string code);
    /// <summary>
    /// Retrieves a list of medicines that match the provided codes or notes.
    /// </summary>
    /// <param name="codeNote">A list of strings representing the codes or notes used to look up medicines.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of <see cref="Medicine"/> objects matching the provided codes or notes.</returns>
    Task<List<Medicine>> GetByCodeOrNote(List<string> codeNote);
    /// <summary>
    /// Retrieves a medicine by its name, returning null if no matching medicine is found.
    /// </summary>
    /// <param name="name">The name of the medicine to look up.</param>
    /// <returns>A task that represents the asynchronous operation, containing the matching <see cref="Medicine"/> or null if not found.</returns>
    Task<Medicine?> GetByName(string name);
    /// <summary>
    /// Retrieves the medicines associated with the specified patient treatments.
    /// </summary>
    /// <param name="treatments">The collection of patient treatments, which may include null entries, whose medicines are to be obtained.</param>
    /// <returns>A task that represents the asynchronous operation, containing the collection of medicines linked to the provided treatments.</returns>
    Task<IEnumerable<Medicine>> GetMedicinesOfTreatments(IEnumerable<PatientTreatment?> treatments);
    /// <summary>
    /// Asynchronously retrieves the collection of active medicines associated with the specified patient.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose active medicines are being queried.</param>
    /// <returns>A task that represents the asynchronous operation, containing an enumerable collection of active <see cref="Medicine"/> records for the patient.</returns>
    Task<IEnumerable<Medicine>> GetActiveMedicinesByPatient(ObjectId patientId);
    /// <summary>
    /// Retrieves a paginated list of medicines based on the provided filter criteria.
    /// </summary>
    /// <param name="filter">The pagination filter containing page size, page number, and optional search criteria.</param>
    /// <returns>A task that represents the asynchronous operation, containing a <see cref="PaginationResponse{T}"/> with the requested <see cref="Medicine"/> items and pagination metadata.</returns>
    Task<PaginationResponse<Medicine>> GetPaginatedMedicines(PaginationFilter filter);
    /// <summary>
    /// Asynchronously retrieves all medicines from the data store.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation, containing a list of all <see cref="Medicine"/> entities.</returns>
    Task<List<Medicine>> GetAll();
    /// <summary>
    /// Retrieves a medicine by its unique identifier.
    /// </summary>
    /// <param name="medicineId">The unique identifier of the medicine to retrieve.</param>
    /// <returns>A task that represents the asynchronous operation, containing the <see cref="Medicine"/> if found; otherwise, <c>null</c>.</returns>
    Task<Medicine?> GetMedicineById(ObjectId medicineId);
    /// <summary>
    /// Asynchronously posts a new medicine and returns the created medicine, or null if the operation fails.
    /// </summary>
    /// <param name="medicine">The medicine entity to be posted.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the posted <see cref="Medicine"/>, or null if the medicine could not be posted.</returns>
    Task<Medicine?> PostMedicine(Medicine medicine);
    /// <summary>
    /// Updates an existing medicine in the data store and returns the updated entity, or <c>null</c> if no matching medicine was found.
    /// </summary>
    /// <param name="medicine">The medicine entity containing the updated values to be persisted.</param>
    /// <returns>A task that represents the asynchronous update operation. The result is the updated <see cref="Medicine"/> when the update succeeds, or <c>null</c> when the medicine does not exist.</returns>
    Task<Medicine?> UpdateMedicine(Medicine medicine);
    /// <summary>
    /// Deletes a medicine record identified by the specified identifier.
    /// </summary>
    /// <param name="medicineId">The unique identifier of the medicine to delete.</param>
    Task DeleteMedicineById(ObjectId medicineId);
    /// <summary>
    /// Asynchronously retrieves all available types as a list of string identifiers.
    /// </summary>
    /// <returns>A task representing the asynchronous operation, containing a list of type identifiers.</returns>
    Task<List<string>> GetAllTypes();
    /// <summary>
    /// Asynchronously retrieves all available groups, returning their identifiers or names as a list of strings.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of strings representing all groups.</returns>
    Task<List<string>> GetAllGroups();
    /// <summary>
    /// Asynchronously retrieves all available names.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of all names.</returns>
    Task<List<string>> GetAllNames();
    /// <summary>
    /// Asynchronously retrieves the complete list of available codes from the data source.
    /// </summary>
    /// <returns>A task representing the asynchronous operation, containing a list of code strings.</returns>
    Task<List<string>> GetAllCodes();
}