using adas_core.Domain.Enums;
using adas_core.Domain.Models.DTO;
using adas_core.Domain.Models.DTO.Display;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.Masters;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Models.Responses;
using MongoDB.Bson;

namespace adas_core.Application.Services.Interfaces;

public interface IDisplayService
{
    //Task<List<DisplayWithPermissionsDto>> GetAll(string? userName, List<Authorization> displayIdByAuthorities);
    /// <summary>
    /// Asynchronously retrieves all displays in a compact format containing only minimal identifying information.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of <see cref="DisplayMinimalDto"/> objects representing all available displays in a compact projection.</returns>
    Task<List<DisplayMinimalDto>> GetAllCompact();
    /// <summary>
    /// Retrieves all displays along with their associated permissions for the specified user.
    /// When <paramref name="userName"/> is null, the behavior is determined by the underlying implementation (e.g., returning all displays or an empty result).
    /// </summary>
    /// <param name="userName">The username used to look up the associated displays and permissions. May be null.</param>
    /// <returns>A task that represents the asynchronous operation, containing a list of <see cref="DisplayWithPermissionsDto"/> entries for the user.</returns>
    Task<List<DisplayWithPermissionsDto>> GetAllByUser(string? userName);
    /// <summary>
    /// Asynchronously retrieves a list of <see cref="Display"/> entries filtered by the specified display type.
    /// </summary>
    /// <param name="type">The display type used to filter the returned collection.</param>
    /// <returns>A task that represents the asynchronous operation, containing the list of <see cref="Display"/> items matching the specified type.</returns>
    Task<List<Display>> GetByType(DisplayConfigEnums.DisplayType type);
    /// <summary>
    /// Asynchronously retrieves the list of displays associated with the specified point of care.
    /// </summary>
    /// <param name="pointOfCare">The point of care used to filter the displays to be returned.</param>
    /// <returns>A task that represents the asynchronous operation, containing the list of <see cref="Display"/> items linked to the given point of care.</returns>
    Task<List<Display>> GetByPointOfCare(PointOfCare pointOfCare);
    /// <summary>
    /// Retrieves a list of displays associated with the specified configuration identifier.
    /// </summary>
    /// <param name="configId">The unique identifier of the configuration used to filter the displays.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of displays matching the specified configuration identifier.</returns>
    Task<List<Display>> GetByConfigId(ObjectId configId);
    /// <summary>
    /// Retrieves a list of <see cref="Display"/> entities associated with the specified card configuration identifier.
    /// </summary>
    /// <param name="configId">The unique identifier of the card configuration whose associated displays are to be retrieved.</param>
    /// <returns>A task that represents the asynchronous operation, containing a list of <see cref="Display"/> objects linked to the given card configuration.</returns>
    Task<List<Display>> GetByCardConfigId(ObjectId configId);

    // Task<List<Display>> GetByUser();
    /// <summary>
    /// Retrieves a <see cref="Display"/> entity by its name asynchronously.
    /// Returns <c>null</c> when no matching display is found.
    /// </summary>
    /// <param name="name">The name of the display to look up.</param>
    /// <returns>A <see cref="Task{Display}"/> that resolves to the matching <see cref="Display"/>, or <c>null</c> if none is found.</returns>
    Task<Display?> GetByName(string name);
    /// <summary>
    /// Retrieves a <see cref="Display"/> entity by its unique identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the display to retrieve.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="Display"/> if found; otherwise, <c>null</c>.</returns>
    Task<Display?> GetById(ObjectId id);
    /// <summary>
    /// Asynchronously retrieves a display representation of an entity along with its associated permissions, localized for the specified locale.
    /// </summary>
    /// <param name="id">The unique identifier of the entity to retrieve.</param>
    /// <param name="localeEnum">The locale used to localize the returned display data.</param>
    /// <returns>A task that represents the asynchronous operation, containing the localized display data with permissions.</returns>
    Task<DisplayWithPermissionsDto> GetByIdWithPermissions(ObjectId id, LocaleEnum localeEnum);
    /// <summary>
    /// Asynchronously counts the number of displays associated with the specified unit identifier.
    /// </summary>
    /// <param name="unitId">The unique identifier of the unit whose displays should be counted.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the count of displays linked to the specified unit.</returns>
    Task<long> CountDisplaysByUnitId(ObjectId unitId);

    /// <summary>
    /// Retrieves the display identified by <paramref name="id"/>, optionally populating related data such as point-of-care, patient, display list, and display configuration based on the corresponding fill flags.
    /// </summary>
    /// <param name="id">The identifier of the display to retrieve.</param>
    /// <param name="userName">The name of the user requesting the display, used for authorization checks.</param>
    /// <param name="authorizations">Optional collection of authorizations used to control access to the display and its related data.</param>
    /// <param name="locale">Optional locale used to localize the returned display information.</param>
    /// <param name="fillPointOfCare">When <c>true</c>, includes the associated point-of-care data in the result.</param>
    /// <param name="fillPatientData">When <c>true</c>, includes the associated patient data in the result.</param>
    /// <param name="fillDisplayList">When <c>true</c>, includes the display list in the result.</param>
    /// <param name="fillDisplayConfig">When <c>true</c>, includes the display configuration in the result.</param>
    /// <param name="ct">Token used to cancel the asynchronous operation.</param>
    /// <returns>A <see cref="Task{T}"/> that resolves to the <see cref="Display"/> if found, or <c>null</c> if no display matches the specified <paramref name="id"/>.</returns>
    Task<Display?> GetInfo(
            ObjectId id,
            string? userName,
            List<Authorization>? authorizations,
            LocaleEnum? locale,
            bool fillPointOfCare = true,
            bool fillPatientData = false,
            bool fillDisplayList = true,
            bool fillDisplayConfig = true,
            CancellationToken ct = default
        );
    

    /// <summary>
    /// Retrieves a list of minimal display sections filtered by display type, current display context, user name, and the provided authorizations.
    /// </summary>
    /// <param name="type">The display type used to filter the available sections.</param>
    /// <param name="currentDisplay">The identifier of the current display, or <c>null</c> when no display is selected.</param>
    /// <param name="userName">The user name used to resolve user-specific sections, or <c>null</c> if not applicable.</param>
    /// <param name="authorizations">The list of authorizations used to authorize and filter the returned sections, or <c>null</c> if no authorization filtering is required.</param>
    /// <returns>A task that yields the list of <see cref="MinimalDisplaySection"/> instances matching the supplied criteria.</returns>
    Task<List<MinimalDisplaySection>> GetDisplaySectionByUser(
            DisplayConfigEnums.DisplayType type,
            ObjectId? currentDisplay,
            string? userName,
            List<Authorization>? authorizations);

    /// <summary>
    /// Asynchronously retrieves all display sections as a minimal display list.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation, containing the <see cref="MinimalDisplayListDto"/> with the display section data.</returns>
    Task<MinimalDisplayListDto> GetAllDisplaySection();
    /// <summary>
    /// Retrieves a list of <see cref="Display"/> records associated with the specified unit identifier.
    /// </summary>
    /// <param name="id">The <see cref="ObjectId"/> that identifies the unit whose displays are being requested.</param>
    /// <returns>A task that represents the asynchronous operation, containing a <see cref="List{Display}"/> of displays linked to the given unit.</returns>
    Task<List<Display>> GetByUnitId(ObjectId id);
    /// <summary>
    /// Retrieves all available Points of Contact (POCs) along with their associated unit information, optionally filtered by the provided display identifiers and allowing exclusion of virtual entries.
    /// </summary>
    /// <param name="displayIds">The list of display identifiers used to filter the available POCs.</param>
    /// <param name="excludeVirtual">When set to <c>true</c>, excludes virtual POCs from the results; otherwise, virtual POCs are included.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a <see cref="PocAndUnitDto"/> with the matching POCs and their unit details.</returns>
    Task<PocAndUnitDto> GetAllAvailablePoc(List<string> displayIds, bool excludeVirtual = false);
    /// <summary>
    /// Asynchronously retrieves all Points of Care (POCs) associated with the specified display identifier.
    /// </summary>
    /// <param name="id">The display identifier used to look up the associated Points of Care.</param>
    /// <returns>A task representing the asynchronous operation, containing a list of Points of Care matching the specified display identifier.</returns>
    Task<List<PointOfCare>> GetAllPocsByDisplayId(ObjectId id);
    /// <summary>
    /// Inserts a new display record into the data store and returns the persisted entity.
    /// </summary>
    /// <param name="display">The display entity to insert.</param>
    /// <returns>A task that represents the asynchronous operation, containing the inserted <see cref="Display"/>.</returns>
    Task<Display> InsertOne(Display display);
    /// <summary>
    /// Asynchronously inserts a single test <see cref="Display"/> record and returns the persisted result.
    /// </summary>
    /// <returns>A <see cref="Task{Display}"/> that represents the asynchronous insert operation, containing the inserted <see cref="Display"/>.</returns>
    Task<Display> InsertOneTest();
    /// <summary>
    /// Updates the configuration of an existing display using the provided new configuration.
    /// </summary>
    /// <param name="oldDisplay">The current display whose configuration will be updated.</param>
    /// <param name="newDisplayConfig">The new display configuration to apply, or null to leave the configuration unchanged.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the updated <see cref="Display"/>, or null if the update was not performed.</returns>
    Task<Display?> UpdateConfig(Display oldDisplay, DisplayConfig? newDisplayConfig);
    /// <summary>
    /// Updates the configuration identifier associated with the specified display.
    /// </summary>
    /// <param name="oldDisplay">The existing display whose configuration identifier will be updated.</param>
    /// <param name="configId">The new configuration identifier to associate with the display.</param>
    /// <returns>A task that resolves to the updated <see cref="Display"/>, or <c>null</c> if no result is available.</returns>
    Task<Display?> UpdateConfigId(Display oldDisplay, ObjectId configId);
    /// <summary>
    /// Updates the point of care list associated with the specified object identifier, replacing or merging it with the provided list of point of care object identifiers.
    /// </summary>
    /// <param name="objectId">The identifier of the object whose point of care list is being updated.</param>
    /// <param name="listPocObId">The collection of point of care object identifiers to apply to the target object.</param>
    /// <returns>A task that represents the asynchronous operation, containing the resulting <see cref="Display"/> when the update succeeds, or <c>null</c> when no matching object is found.</returns>
    Task<Display?> UpdatePointOfCareList(ObjectId objectId, List<ObjectId> listPocObId);
    /// <summary>
    /// Updates the configuration preset associated with the specified display using the provided configuration display.
    /// </summary>
    /// <param name="objectIdDisplay">The unique identifier of the display whose configuration preset will be updated.</param>
    /// <param name="objectIdConfigDisplay">The unique identifier of the configuration display to apply as the preset.</param>
    /// <returns>A task that resolves to the updated <see cref="Display"/>, or <c>null</c> if no matching display is found.</returns>
    Task<Display?> UpdateConfigPreset(ObjectId objectIdDisplay, ObjectId objectIdConfigDisplay);
    /// <summary>
    /// Updates the name of the entity identified by the given identifier and returns the resulting <see cref="Display"/>.
    /// </summary>
    /// <param name="id">The identifier of the entity whose name should be updated.</param>
    /// <param name="name">The new name to apply to the entity.</param>
    /// <returns>A task that represents the asynchronous update operation, containing the updated <see cref="Display"/> or <c>null</c> if no entity was found.</returns>
    Task<Display?> UpdateName(ObjectId id, string name);
    /// <summary>
    /// Retrieves a paginated collection of displays based on the provided filter criteria.
    /// </summary>
    /// <param name="filter">The pagination filter that defines the page size, page number, and any additional filtering criteria for the display results.</param>
    /// <returns>A task that represents the asynchronous operation, containing a <see cref="PaginationResponse{Display}"/> with the requested page of displays and pagination metadata.</returns>
    Task<PaginationResponse<Display>> GetPaginatedDisplays(PaginationFilter filter);
    /// <summary>
    /// Asynchronously deletes the display identified by the specified identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the display to delete.</param>
    /// <returns>A task that represents the asynchronous operation, containing a value indicating whether the display was successfully deleted.</returns>
    Task<bool> DeleteDisplay(ObjectId id);
    /// <summary>
    /// Retrieves the list of display configuration locations associated with the specified display configuration.
    /// </summary>
    /// <param name="displayConfigId">The unique identifier of the display configuration whose locations are being retrieved.</param>
    /// <returns>A task that represents the asynchronous operation, containing a list of <see cref="DisplayConfigLocationDto"/> objects for the specified display configuration.</returns>
    Task<List<DisplayConfigLocationDto>> GetDisplayConfigLocations(ObjectId displayConfigId);
    /// <summary>
    /// Asynchronously determines whether the specified display configuration is currently in use.
    /// </summary>
    /// <param name="displayConfigId">The identifier of the display configuration to check.</param>
    /// <returns>A task that represents the asynchronous operation. The task result is <c>true</c> if the display configuration is in use; otherwise, <c>false</c>.</returns>
    Task<bool> IsDisplayConfigInUse(ObjectId displayConfigId);
    /// <summary>
    /// Deletes display records associated with the specified unit identifier.
    /// </summary>
    /// <param name="unitId">The identifier of the unit whose displays should be removed.</param>
    Task DeleteDisplaysByUnitId(ObjectId unitId);
}