using System.IdentityModel.Tokens.Jwt;
using adas_core.Authentication.Models;
using adas_core.Domain.Models.DTO;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Models.Responses;
using Microsoft.IdentityModel.Tokens;
using MongoDB.Bson;

namespace adas_core.Authentication.Interfaces;

public interface IUserService
{
    static readonly string TokenTypeUser = "user";
    static readonly string TokenTypeRefresh = "refresh";

    /// <summary>
    /// Authenticates a user with the provided credentials and returns a token result upon successful login.
    /// </summary>
    /// <param name="username">The username of the user attempting to log in.</param>
    /// <param name="password">The password associated with the specified username.</param>
    /// <returns>A task that represents the asynchronous login operation, containing the <see cref="TokenResult"/> with the authentication token information.</returns>
    Task<TokenResult> Login(string username, string password);
    /// <summary>
    /// Authenticates a user based on the provided username and password and returns the corresponding user.
    /// </summary>
    /// <param name="username">The username of the user to authenticate.</param>
    /// <param name="password">The password of the user to authenticate.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the authenticated <see cref="User"/>.</returns>
    Task<User> GetUser(string username, string password);
    /// <summary>
    /// Refreshes an authentication token using the provided refresh token and returns the resulting token information.
    /// </summary>
    /// <param name="refreshToken">The refresh token used to obtain a new access token.</param>
    /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous operation, containing the <see cref="TokenResult"/> with the refreshed token details.</returns>
    Task<TokenResult> RefreshToken(string refreshToken);

    /// <summary>
    /// Authenticates a user by exchanging a provided access token for a login result.
    /// </summary>
    /// <param name="token">The access token used to authenticate the user.</param>
    /// <returns>A task that represents the asynchronous login operation, containing the <see cref="TokenResult"/> with the outcome of the authentication.</returns>
    Task<TokenResult> LoginWithAccessToken(string token);
    /// <summary>
    /// Validates the specified token according to its type and outputs the corresponding <see cref="SecurityToken"/>.
    /// </summary>
    /// <param name="token">The token string to be validated.</param>
    /// <param name="tokenType">The type of the token, used to determine the appropriate validation strategy.</param>
    /// <param name="securityToken">When the method returns, contains the validated <see cref="SecurityToken"/> if validation succeeds.</param>
    void ValidateToken(string token, string tokenType, out SecurityToken securityToken);
    /// <summary>
    /// Retrieves the user associated with the provided JWT security token.
    /// Returns <c>null</c> if the token is <c>null</c> or if no matching user is found.
    /// </summary>
    /// <param name="jwtToken">The JWT security token used to identify the user. May be <c>null</c>.</param>
    /// <returns>A task that resolves to the <see cref="User"/> associated with the token, or <c>null</c> if the token is invalid or no user matches.</returns>
    Task<User?> GetUserByToken(JwtSecurityToken? jwtToken);
    /// <summary>
    /// Asynchronously retrieves a user by validating a CAS (Central Authentication Service) ticket against the specified service.
    /// </summary>
    /// <param name="service">The service URL or identifier that the ticket was issued for and must be validated against.</param>
    /// <param name="ticket">The CAS ticket string used to authenticate and identify the user.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the associated <see cref="User"/> if the ticket is valid, or <c>null</c> if the user cannot be found.</returns>
    Task<User?> GetUserByCasTicket(string service, string ticket);
    /// <summary>
    /// Asynchronously generates a JSON Web Token (JWT) for the specified user and returns the token result.
    /// </summary>
    /// <param name="user">The user for whom the JWT is being generated.</param>
    /// <returns>A task that represents the asynchronous operation, containing the <see cref="TokenResult"/> with the generated token details.</returns>
    Task<TokenResult> GenerateJwt(User user);
    /// <summary>
    /// Asynchronously retrieves all users from the data store.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of all <see cref="User"/> entities.</returns>
    Task<List<User>> GetAll();
    /// <summary>
    /// Asynchronously retrieves a user by their unique identifier, returning <c>null</c> when no user matches the provided id.
    /// </summary>
    /// <param name="id">The unique <see cref="ObjectId"/> identifier of the user to look up.</param>
    /// <returns>A task that resolves to the matching <see cref="User"/>, or <c>null</c> if no user is found for the given id.</returns>
    Task<User?> GetUserById(ObjectId id);
    /// <summary>
    /// Asynchronously retrieves a user by their unique username, returning null when no matching user is found.
    /// </summary>
    /// <param name="name">The username used to look up the user.</param>
    /// <returns>A task that represents the asynchronous operation, containing the matching user if found; otherwise, null.</returns>
    Task<User?> GetUserByUserName(string name);
    /// <summary>
    /// Asynchronously retrieves a user matching the specified name, returning <c>null</c> when no matching user is found.
    /// </summary>
    /// <param name="name">The name used to look up the user.</param>
    /// <returns>A task that resolves to the matching <see cref="User"/>, or <c>null</c> if no user with the given name exists.</returns>
    Task<User?> GetUserByName(string name);
    /// <summary>
    /// Creates a user from the provided LDAP user entry.
    /// </summary>
    /// <param name="userEntryLdap">The LDAP user entry used to create the user.</param>
    /// <returns>A task that represents the asynchronous create operation, containing the created <see cref="User"/> or <c>null</c>.</returns>
    Task<User?> CreateUser(User userEntryLdap);
    /// <summary>
    /// Creates a new user based on the provided user data, typically originating from an incoming request.
    /// Returns the newly created user, or <see langword="null"/> if the user could not be created.
    /// </summary>
    /// <param name="user">The user data to use for creating the new user.</param>
    /// <returns>A task that represents the asynchronous operation. The result is the created <see cref="User"/>, or <see langword="null"/> if creation failed.</returns>
    Task<User?> CreateNewUserByRequest(User user);

    /// <summary>
    /// Creates a new user together with the associated authorities based on the supplied data transfer object.
    /// </summary>
    /// <param name="createUserWithAuthDto">The data transfer object containing the information required to create the user and its authorities.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the created <see cref="User"/> instance, or <c>null</c> if no user was created.</returns>
    Task<User?> CreateNewUserWithAuthorities(CreateUserWithAuthDto createUserWithAuthDto);
    /// <summary>
    /// Updates an existing user along with the associated authorities, optionally updating the password.
    /// </summary>
    /// <param name="createUserWithAuthDto">The data transfer object containing the user information and authorities to update.</param>
    /// <param name="updatePass">A flag indicating whether the user's password should be updated as part of the operation.</param>
    /// <returns>A task that represents the asynchronous operation, containing the updated <see cref="User"/> or <c>null</c> if the user was not found.</returns>
    Task<User?> UpdateUserWithAuthorities(UpdateUserWithAuthDto createUserWithAuthDto, bool updatePass);
    /// <summary>
    /// Updates a user's information based on the provided user data, with an option to include password updates.
    /// </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 be updated during this operation.</param>
    /// <returns>A task that returns the updated <see cref="User"/>, or null if the user could not be found.</returns>
    Task<User?> UpdateUsersByRequest(User user, bool updatePass);
    /// <summary>
    /// Updates the password for the user identified by the specified identifier, verifying the old password before applying the new one.
    /// </summary>
    /// <param name="id">The unique identifier of the user whose password will be updated.</param>
    /// <param name="oldPassword">The user's current password, used to verify the request.</param>
    /// <param name="newPassword">The new password to set for the user.</param>
    /// <returns>A task that represents the asynchronous operation. The task result is <c>true</c> if the password was updated successfully; otherwise, <c>false</c>.</returns>
    Task<bool> UpdateUserPassword(ObjectId id, string oldPassword, string newPassword);
    /// <summary>
    /// Asynchronously deletes a user identified by the specified identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the user to delete.</param>
    /// <returns>A task that represents the asynchronous operation, containing a value indicating whether the user was successfully deleted.</returns>
    Task<bool> DeleteUser(ObjectId id);
    /// <summary>
    /// Retrieves a paginated list of users based on the provided pagination filter configuration.
    /// </summary>
    /// <param name="config">The pagination filter that defines paging parameters such as page number and page size.</param>
    /// <returns>A task that represents the asynchronous operation, containing the paginated response of <see cref="User"/> entries.</returns>
    Task<PaginationResponse<User>> GetPaginatedUsers(PaginationFilter config);
    /// <summary>
    /// Asynchronously creates a new authority based on the provided authorization data.
    /// </summary>
    /// <param name="auth">The authorization information used to create the new authority.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the created <see cref="Authorization"/>.</returns>
    Task<Authorization> CreateNewAuthority(Authorization auth);
    /// <summary>
    /// Asynchronously deletes an authority identified by the specified identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the authority to delete.</param>
    /// <returns>A task that represents the asynchronous delete operation. The task result contains a boolean indicating whether the authority was successfully deleted.</returns>
    Task<bool> DeleteAuthority(string id);
    /// <summary>
    /// Updates the authority information based on the provided authorization data.
    /// </summary>
    /// <param name="authorization">The authorization entity containing the authority details to be updated.</param>
    /// <returns>A task that represents the asynchronous operation. The task result is <c>true</c> if the update was successful; otherwise, <c>false</c>.</returns>
    Task<bool> UpdateAuthority(Authorization authorization);
    /// <summary>
    /// Authenticates the user using the provided access token and returns the resulting token information.
    /// </summary>
    /// <param name="token">The access token used to perform the login.</param>
    /// <returns>A task that represents the asynchronous login operation, containing the token result.</returns>
    Task<TokenResult> LoginWithGivenAccessToken(string token);
}