#ifndef _diffusion_security_h_
#define _diffusion_security_h_ 1

/*
 * Copyright © 2014 - 2025 DiffusionData Ltd., All Rights Reserved.
 *
 * Use is subject to licence terms.
 *
 * NOTICE: All information contained herein is, and remains the
 * property of DiffusionData. The intellectual and technical
 * concepts contained herein are proprietary to DiffusionData and
 * may be covered by U.S. and Foreign Patents, patents in process, and
 * are protected by trade secret or copyright law.
 */

/**
 * @file security.h
 *
 * Security feature.
 */
#include "diffusion-api-error.h"
#include "session.h"


/**
 * @brief Callback indicating that a response has been received to a
 * re-authentication request.
 *
 * @param session The current active session.
 * @param success Indicates if the reauthentication was a success or not.
 * @param context User-supplied context from the original reauthentication request.
 *
 * @return HANDLER_SUCCESS or HANDLER_FAILURE.
 *
 * @since 6.12
 */
typedef int (*on_reauthenticate_cb)(const SESSION_T *session, bool success, void *context);


/**
 * @brief Callback indicating that a response has been received to a
 * change principal request.
 *
 * @param session The current active session.
 * @param context User-supplied context from the original change_principal() call.
 *
 * @return HANDLER_SUCCESS or HANDLER_FAILURE.
 */
typedef int (*on_change_principal_cb)(SESSION_T *session, void *context);


/**
 * @brief Callback for `diffusion_get_global_permissions`.
 *
 * @param global_permissions a `SET_T` containing `GLOBAL_PERMISSIONS_T`s
 * @param context            User-supplied context from the originating call.
 *
 * @return HANDLER_SUCCESS or HANDLER_FAILURE.
 */
typedef int (*on_get_global_permissions_cb)(const SET_T *global_permissions, void *context);


/**
 * @brief Callback for `diffusion_get_path_permissions`.
 *
 * @param path_permissions  a `SET_T` containing `PATH_PERMISSIONS_T`s
 * @param context            User-supplied context from the originating call.
 *
 * @return HANDLER_SUCCESS or HANDLER_FAILURE.
 *
 * @since 6.5
 */
typedef int (*on_get_path_permissions_cb)(const SET_T *path_permissions, void *context);


/**
 * @brief Structure holding callbacks to be invoked after a request
 * to reauthenticate has been sent to and processed by Diffusion.
 *
 * @since 6.12
 */
#define DIFFUSION_REAUTHENTICATE_HANDLERS                               \
    /** Called when the reauthentication request has been processed. */ \
    on_reauthenticate_cb on_reauthenticate;                             \
    /** Standard service error handler callback. */                     \
    ERROR_HANDLER_T on_error;                                           \
    /** Standard service discard handler callback. */                   \
    DISCARD_HANDLER_T on_discard;


/**
 * @brief Structure holding callbacks to be invoked after a request
 * to change the principal has been sent to and processed by
 * Diffusion.
 */
#define CHANGE_PRINCIPAL_HANDLERS                                       \
    /** Called when the change principal request is successful. */      \
    on_change_principal_cb on_change_principal;                         \
    /** Called when the change principal request results in failure. */ \
    on_change_principal_cb on_change_principal_failure;                 \
    /** Standard service error handler callback. */                     \
    ERROR_HANDLER_T on_error;                                           \
    /** Standard service discard handler callback. */                   \
    DISCARD_HANDLER_T on_discard;


/**
 * @brief Structure supplied when issuing a change_principal() request.
 *
 * @since 6.12
 */
typedef struct reauthenticate_params_s
{
    DIFFUSION_REAUTHENTICATE_HANDLERS

    /// The new principal (username).
    const char *principal;

    /// The credentials associated with the principal.
    const CREDENTIALS_T *credentials;

    /// a map of the proposed user session properties.
    /// The supplied properties will be validated during authentication and
    /// may be discarded or changed.
    /// If no user properties are required, this property can be set to NULL.
    HASH_T *properties;

    /// User-supplied context to return to callbacks.
    void *context;
} DIFFUSION_REAUTHENTICATE_PARAMS_T;


/**
 * @brief Structure supplied when issuing a change_principal() request.
 */
typedef struct change_principal_params_s
{
    CHANGE_PRINCIPAL_HANDLERS
    /// The new principal (username).
    const char *principal;
    /// The credentials associated with the principal.
    const CREDENTIALS_T *credentials;
    /// User-supplied context to return to callbacks.
    void *context;
} CHANGE_PRINCIPAL_PARAMS_T;


/**
 * @brief Structure supplied when issuing a `diffusion_get_global_permissions` request.
 */
typedef struct diffusion_get_global_permissions_params_s
{
    /// Callback
    on_get_global_permissions_cb on_global_permissions;
    /// Callback to handle errors. Can be NULL.
    ERROR_HANDLER_T on_error;
    /// Callback to handle discards. Can be NULL.
    DISCARD_HANDLER_T on_discard;
    /// User supplied context. Can be NULL.
    void *context;
} DIFFUSION_GET_GLOBAL_PERMISSIONS_PARAMS_T;


/**
 * @brief Structure supplied when issuing a `diffusion_get_path_permissions` request.
 */
typedef struct diffusion_get_path_permissions_params_s
{
    /// The topic path to retrieve permissions for.
    const char *path;
    /// Callback
    on_get_path_permissions_cb on_path_permissions;
    /// Callback to handle errors. Can be NULL.
    ERROR_HANDLER_T on_error;
    /// Callback to handle discards. Can be NULL.
    DISCARD_HANDLER_T on_discard;
    /// User supplied context. Can be NULL.
    void *context;
} DIFFUSION_GET_PATH_PERMISSIONS_PARAMS_T;


/**
 * @ingroup PublicAPI_Security
 *
 * @brief Re-authenticate the session.
 *
 * This may be used to change the principal for the session, or to
 * re-authenticate the session before it expires.
 *
 * A session may determine when it is due to expire by querying the value of
 * the `EXPIRY_TIME` session property using `getSessionProperties`.
 * If this property is not present the session will not expire and there is no
 * need to re-authenticate unless the principal in use is to be changed.
 *
 * @param session       The session handle.
 * @param params        Parameters defining the request and notification callbacks.
 * @param api_error     Populated on API error. Can be NULL.
 *
 * @return true if the operation was successful. False, otherwise. In this case, if
 *         a non-NULL `api_error` pointer has been provided, this will be populated
 *         with the error information and should be freed with `diffusion_api_error_free`.
 */
bool diffusion_reauthenticate(
    SESSION_T *session,
    const DIFFUSION_REAUTHENTICATE_PARAMS_T params,
    DIFFUSION_API_ERROR *api_error);


/**
 * @ingroup PublicAPI_Security
 *
 * @brief Issue a request to change the principal for the current (active)
 * session.
 *
 * @param session       The session handle. If NULL, this function has no effect.
 * @param params        Parameters defining the change_principal() request
 *                      and notification callbacks.
 *
 * @deprecated since 6.12.
 *             Use the new `diffusion_reauthenticate` in preference, which
 *             allows user proposed session properties to be supplied.
 *             This method will be removed in a future release.
 */
DEPRECATED(void change_principal(SESSION_T *session, const CHANGE_PRINCIPAL_PARAMS_T params));


/**
 * @ingroup PublicAPI_Security
 *
 * @brief Query the global permissions assigned to the calling session.
 *
 * @param session       The session handle. If NULL, this function returns immediately.
 * @param params        Parameters describing the `diffusion_get_global_permissions`
 *                      request and callback handlers which may be invoked
 *                      in response.
 * @param api_error     Populated on API error. Can be NULL.
 *
 * @return true if the operation was successful. False, otherwise. In this case, if
 *         a non-NULL `api_error` pointer has been provided, this will be populated
 *         with the error information and should be freed with `diffusion_api_error_free`.
 */
bool diffusion_get_global_permissions(

    SESSION_T *session,
    const DIFFUSION_GET_GLOBAL_PERMISSIONS_PARAMS_T params,
    DIFFUSION_API_ERROR *api_error);


/**
 * @ingroup PublicAPI_Security
 *
 * @brief Query the path permissions assigned to the calling session on a given path.
 *
 * @param session       The session handle. If NULL, this function returns immediately.
 * @param params        Parameters describing the `diffusion_get_path_permissions`
 *                      request and callback handlers which may be invoked
 *                      in response.
 * @param api_error     Populated on API error. Can be NULL.
 *
 * @return true if the operation was successful. False, otherwise. In this case, if
 *         a non-NULL `api_error` pointer has been provided, this will be populated
 *         with the error information and should be freed with `diffusion_api_error_free`.
 */
bool diffusion_get_path_permissions(
    SESSION_T *session,
    const DIFFUSION_GET_PATH_PERMISSIONS_PARAMS_T params,
    DIFFUSION_API_ERROR *api_error);

#endif
