using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.MongoModels;
using MongoDB.Bson;
using MongoDB.Driver;

namespace adas_core.Application.Repositories.Interfaces;

public interface IUserRepository : IMongoRepository<User>
{
    /// <summary>
    /// Asynchronously retrieves a user by validating the provided username and password credentials.
    /// Returns the matching user when authentication succeeds, or null if no user matches the supplied credentials.
    /// </summary>
    /// <param name="username">The username used to look up the user account.</param>
    /// <param name="password">The password used to authenticate the user.</param>
    /// <returns>A task that resolves to the authenticated <see cref="User"/>, or null if no user matches the provided credentials.</returns>
    Task<User?> GetUser(string username, string password);
    /// <summary>
    /// Retrieves a user by their unique identifier asynchronously.
    /// </summary>
    /// <param name="id">The unique identifier of the user to retrieve.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="User"/> if found; otherwise, <see langword="null"/>.</returns>
    Task<User?> GetById(ObjectId id);
    /// <summary>
    /// Asynchronously retrieves a user matching the specified username. Returns <c>null</c> if no user is found.
    /// </summary>
    /// <param name="name">The username to look up.</param>
    /// <returns>A task that represents the asynchronous operation, containing the matching <see cref="User"/> or <c>null</c> if not found.</returns>
    Task<User?> GetByUserName(string name);
    /// <summary>
    /// Asynchronously retrieves a user by their name, returning null if no matching user is found.
    /// </summary>
    /// <param name="name">The name of the user to look up.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the user with the specified name, or null if no matching user exists.</returns>
    Task<User?> GetByName(string name);
    /// <summary>
    /// Asynchronously retrieves the user associated with the specified authorities name.
    /// </summary>
    /// <param name="name">The authorities name used to look up the user.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the matching <see cref="User"/> if found; otherwise, <c>null</c>.</returns>
    Task<User?> GetByUserAndAuthoritesName(string name);
    /// <summary>
    /// Updates an existing user in the system, optionally updating the user's password when the <paramref name="updatePass"/> flag is set.
    /// </summary>
    /// <param name="user">The user entity containing the updated information to be persisted.</param>
    /// <param name="updatePass">A flag indicating whether the user's password should also be updated as part of this operation.</param>
    /// <returns>A task that returns the updated <see cref="User"/> entity, or <c>null</c> if the user was not found.</returns>
    Task<User?> UpdateUser(User user, bool updatePass);
    /// <summary>
    /// Retrieves a paginated, fluent queryable collection of <see cref="User"/> entities based on the supplied pagination filter.
    /// </summary>
    /// <param name="filter">The pagination filter that defines paging parameters such as page number and page size.</param>
    /// <returns>An <see cref="IFindFluent{User, User}"/> representing the queryable, paginated user results.</returns>
    IFindFluent<User, User> GetPaginatedUsers(PaginationFilter filter);
    /// <summary>
    /// Retrieves the existing system user, creating a new one if it does not already exist.
    /// </summary>
    /// <returns>The existing or newly created system <see cref="User"/>.</returns>
    Task<User> GetOrCreateSystemUser();
}