/*
 * Copyright (C) 2026 The pgagroal community
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list
 * of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this
 * list of conditions and the following disclaimer in the documentation and/or other
 * materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may
 * be used to endorse or promote products derived from this software without specific
 * prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef PGAGROAL_MANAGEMENT_H
#define PGAGROAL_MANAGEMENT_H

#ifdef __cplusplus
extern "C" {
#endif

#include <pgagroal.h>
#include <json.h>

#include <stdbool.h>
#include <stdlib.h>

#include <openssl/ssl.h>

/**
 * Management header
 */
#define MANAGEMENT_COMPRESSION_NONE  0
#define MANAGEMENT_COMPRESSION_GZIP  1
#define MANAGEMENT_COMPRESSION_ZSTD  2
#define MANAGEMENT_COMPRESSION_LZ4   3
#define MANAGEMENT_COMPRESSION_BZIP2 4

/* Encryption algorithm codes for the management protocol */
#define MANAGEMENT_ENCRYPTION_NONE       0
#define MANAGEMENT_ENCRYPTION_AES256_GCM 1
#define MANAGEMENT_ENCRYPTION_AES192_GCM 2
#define MANAGEMENT_ENCRYPTION_AES128_GCM 3

/**
 * Management categories
 */
#define MANAGEMENT_CATEGORY_HEADER   "Header"
#define MANAGEMENT_CATEGORY_REQUEST  "Request"
#define MANAGEMENT_CATEGORY_RESPONSE "Response"
#define MANAGEMENT_CATEGORY_OUTCOME  "Outcome"

/**
 * Management commands
 */
#define MANAGEMENT_UNKNOWN         0
#define MANAGEMENT_CANCEL_SHUTDOWN 1
#define MANAGEMENT_CONFIG_LS       2
#define MANAGEMENT_CONFIG_GET      3
#define MANAGEMENT_CONFIG_SET      4
#define MANAGEMENT_DETAILS         5
#define MANAGEMENT_DISABLEDB       6
#define MANAGEMENT_ENABLEDB        7
#define MANAGEMENT_FLUSH           8
#define MANAGEMENT_GET_PASSWORD    9
#define MANAGEMENT_GRACEFULLY      10
#define MANAGEMENT_PING            11
#define MANAGEMENT_RELOAD          12
#define MANAGEMENT_CLEAR           13
#define MANAGEMENT_CLEAR_SERVER    14
#define MANAGEMENT_SHUTDOWN        15
#define MANAGEMENT_STATUS          16
#define MANAGEMENT_SWITCH_TO       17
#define MANAGEMENT_CONFIG_ALIAS    18

#define MANAGEMENT_MASTER_KEY      19
#define MANAGEMENT_ADD_USER        20
#define MANAGEMENT_UPDATE_USER     21
#define MANAGEMENT_REMOVE_USER     22
#define MANAGEMENT_LIST_USERS      23
/**
 * Management arguments
 */
#define MANAGEMENT_ARGUMENT_ACTIVE_CONNECTIONS  "ActiveConnections"
#define MANAGEMENT_ARGUMENT_APPNAME             "AppName"
#define MANAGEMENT_ARGUMENT_BEHIND              "Behind"
#define MANAGEMENT_ARGUMENT_CLIENT_VERSION      "ClientVersion"
#define MANAGEMENT_ARGUMENT_COMMAND             "Command"
#define MANAGEMENT_ARGUMENT_COMPRESSION         "Compression"
#define MANAGEMENT_ARGUMENT_CONFIG_KEY          "ConfigKey"
#define MANAGEMENT_ARGUMENT_CONFIG_VALUE        "ConfigValue"
#define MANAGEMENT_ARGUMENT_CONNECTIONS         "Connections"
#define MANAGEMENT_ARGUMENT_DATABASE            "Database"
#define MANAGEMENT_ARGUMENT_DATABASES           "Databases"
#define MANAGEMENT_ARGUMENT_ENABLED             "Enabled"
#define MANAGEMENT_ARGUMENT_ENCRYPTION          "Encryption"
#define MANAGEMENT_ARGUMENT_ERROR               "Error"
#define MANAGEMENT_ARGUMENT_FD                  "FD"
#define MANAGEMENT_ARGUMENT_HOST                "Host"
#define MANAGEMENT_ARGUMENT_INITIAL_CONNECTIONS "InitialConnections"
#define MANAGEMENT_ARGUMENT_LIMITS              "Limits"
#define MANAGEMENT_ARGUMENT_MAJOR_VERSION       "MajorVersion"
#define MANAGEMENT_ARGUMENT_MAX_CONNECTIONS     "MaxConnections"
#define MANAGEMENT_ARGUMENT_MIN_CONNECTIONS     "MinConnections"
#define MANAGEMENT_ARGUMENT_MODE                "Mode"
#define MANAGEMENT_ARGUMENT_NUMBER_OF_SERVERS   "NumberOfServers"
#define MANAGEMENT_ARGUMENT_OUTPUT              "Output"
#define MANAGEMENT_ARGUMENT_PASSWORD            "Password"
#define MANAGEMENT_ARGUMENT_PID                 "PID"
#define MANAGEMENT_ARGUMENT_PORT                "Port"
#define MANAGEMENT_ARGUMENT_PRIMARY             "Primary"
#define MANAGEMENT_ARGUMENT_RESTART             "Restart"
#define MANAGEMENT_ARGUMENT_SERVER              "Server"
#define MANAGEMENT_ARGUMENT_SERVERS             "Servers"
#define MANAGEMENT_ARGUMENT_SERVER_VERSION      "ServerVersion"
#define MANAGEMENT_ARGUMENT_START_TIME          "StartTime"
#define MANAGEMENT_ARGUMENT_STATE               "State"
#define MANAGEMENT_ARGUMENT_SYSTEM_IDENTIFIER   "SystemIdentifier"
#define MANAGEMENT_ARGUMENT_HEALTH              "Health"
#define MANAGEMENT_ARGUMENT_STATUS              "Status"
#define MANAGEMENT_ARGUMENT_TIME                "Time"
#define MANAGEMENT_ARGUMENT_TIMESTAMP           "Timestamp"
#define MANAGEMENT_ARGUMENT_TOTAL_CONNECTIONS   "TotalConnections"
#define MANAGEMENT_ARGUMENT_USERNAME            "Username"

/**
 * Management error
 */
#define MANAGEMENT_ERROR_BAD_PAYLOAD                        1
#define MANAGEMENT_ERROR_UNKNOWN_COMMAND                    2
#define MANAGEMENT_ERROR_ALLOCATION                         3

#define MANAGEMENT_ERROR_METRICS_NOFORK                     100
#define MANAGEMENT_ERROR_METRICS_NETWORK                    101

#define MANAGEMENT_ERROR_FLUSH_NOFORK                       200
#define MANAGEMENT_ERROR_FLUSH_NETWORK                      201

#define MANAGEMENT_ERROR_STATUS_NOFORK                      700
#define MANAGEMENT_ERROR_STATUS_NETWORK                     701

#define MANAGEMENT_ERROR_STATUS_DETAILS_NOFORK              800
#define MANAGEMENT_ERROR_STATUS_DETAILS_NETWORK             801

#define MANAGEMENT_ERROR_CONF_GET_NOFORK                    900
#define MANAGEMENT_ERROR_CONF_GET_NETWORK                   901
#define MANAGEMENT_ERROR_CONF_GET_ERROR                     902

#define MANAGEMENT_ERROR_CONF_SET_NOFORK                    1000
#define MANAGEMENT_ERROR_CONF_SET_NETWORK                   1001
#define MANAGEMENT_ERROR_CONF_SET_ERROR                     1002
#define MANAGEMENT_ERROR_CONF_SET_NOREQUEST                 1003
#define MANAGEMENT_ERROR_CONF_SET_NOCONFIG_KEY_OR_VALUE     1004
#define MANAGEMENT_ERROR_CONF_SET_UNKNOWN_SERVER            1005
#define MANAGEMENT_ERROR_CONF_SET_UNKNOWN_CONFIGURATION_KEY 1006

#define MANAGEMENT_ERROR_CONF_ALIAS_NOFORK                  1200
#define MANAGEMENT_ERROR_CONF_ALIAS_NETWORK                 1201
#define MANAGEMENT_ERROR_CONF_ALIAS_ERROR                   1202

#define MANAGEMENT_ERROR_SWITCH_TO_FAILED                   1300

/**
 * Output formats
 */
#define MANAGEMENT_OUTPUT_FORMAT_TEXT 0
#define MANAGEMENT_OUTPUT_FORMAT_JSON 1
#define MANAGEMENT_OUTPUT_FORMAT_RAW  2

/**
 * Create header for management command
 * @param command The command
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @param json The target json
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_create_header(int32_t command, uint8_t compression, uint8_t encryption, int32_t output_format, struct json** json);

/**
 * Create request for management command
 * @param json The target json
 * @param json The request json
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_create_request(struct json* json, struct json** request);

/**
 * Create success outcome for management command
 * @param json The target json
 * @param start_t The start time of the command
 * @param end_t The end time of the command
 * @param outcome The outcome json
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_create_outcome_success(struct json* json, time_t start_t, time_t end_t, struct json** outcome);

/**
 * Create success outcome for management command
 * @param json The target json
 * @param error The error code
 * @param outcome The outcome json
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_create_outcome_failure(struct json* json, int32_t error, struct json** outcome);

/**
 * Management operation: Flush the pool
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param mode The flush mode
 * @param database The database
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_flush(SSL* ssl, int socket, int32_t mode, char* database, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Enable database
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param database The database name
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_enabledb(SSL* ssl, int socket, char* database, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Disable database
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param database The database name
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_disabledb(SSL* ssl, int socket, char* database, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Gracefully
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_gracefully(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Stop
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_shutdown(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Cancel shutdown
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_cancel_shutdown(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Status
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_status(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Details
 * @param ssl The SSL connection
 * @param socket The socket
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_details(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: isalive
 * @param socket The socket
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_ping(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Clear
 * @param ssl The SSL connection
 * @param socket The socket
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_clear(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Clear server
 * @param ssl The SSL connection
 * @param socket The socket
 * @param server The server
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_clear_server(SSL* ssl, int socket, char* server, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Switch to
 * @param ssl The SSL connection
 * @param socket The socket
 * @param server The server
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_switch_to(SSL* ssl, int socket, char* server, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Management operation: Reload
 * @param ssl The SSL connection
 * @param socket The socket
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_reload(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/* /\** */
/*  * Management operation: get a configuration setting. */
/*  * This function sends over the socket the message to get a configuration */
/*  * value. */
/*  * In particular, the message block for the action config_get is sent, */
/*  * then the size of the configuration parameter to get (e.g., `max_connections`) */
/*  * and last the parameter name itself. */
/*  * */
/*  * @param ssl the SSL connection */
/*  * @param socket the socket file descriptor */
/*  * @param config_key the name of the configuration parameter to get back */
/*  * @param compression The compress method for wire protocol */
/*  * @param encryption The encrypt method for wire protocol */
/*  * @param output_format The output format */
/*  * @return 0 on success, 1 on error */
/*  *\/ */
/* int */
/* pgagroal_management_request_config_get(SSL* ssl, int socket, char* config_key, uint8_t compression, uint8_t encryption, int32_t output_format); */

/* /\** */
/*  * Management operation: set a configuration setting. */
/*  * This function sends over the socket the message to set a configuration */
/*  * value. */
/*  * In particular, the message block for the action config_set is sent, */
/*  * then the size of the configuration parameter to set (e.g., `max_connections`), */
/*  * then the parameter name. At this point another couple of "size" and "value" is */
/*  * sent with the size of the value to set and its value. */
/*  * */
/*  * @param ssl the SSL connection */
/*  * @param socket the socket file descriptor */
/*  * @param config_key the name of the configuration parameter to set */
/*  * @param config_value the value to set for the new parameter */
/*  * @param compression The compress method for wire protocol */
/*  * @param encryption The encrypt method for wire protocol */
/*  * @param output_format The output format */
/*  * @return 0 on success, 1 on error */
/*  *\/ */
/* int */
/* pgagroal_management_request_config_set(SSL* ssl, int socket, char* config_key, char* config_value, uint8_t compression, uint8_t encryption, int32_t output_format); */

/**
 * Create a conf ls request
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_conf_ls(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Create a conf ls request
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_conf_get(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Create a conf get request
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param config_key The configuration key
 * @param config_value The configuration value
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_conf_set(SSL* ssl, int socket, char* config_key, char* config_value, uint8_t compression, uint8_t encryption, int32_t output_format);

int
pgagroal_management_config_alias(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, struct json* payload);

/**
 * Get the frontend password of a user
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param user The frontend user
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param output_format The output format
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_request_get_password(SSL* ssl, int socket, char* username, uint8_t compression, uint8_t encryption, int32_t output_format);

// Add around line 170:
int
pgagroal_management_request_conf_alias(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, int32_t output_format);

/**
 * Create an ok response
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param start_time The start time
 * @param end_time The end time
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param payload The full payload
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_response_ok(SSL* ssl, int socket, time_t start_time, time_t end_time, uint8_t compression, uint8_t encryption, struct json* payload);

/**
 * Create an error response
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param server The server
 * @param error The error code
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param payload The full payload
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_response_error(SSL* ssl, int socket, char* server, int32_t error, uint8_t compression, uint8_t encryption, struct json* payload);

/**
 * Create a response
 * @param json The JSON structure
 * @param server The server
 * @param response The response
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_create_response(struct json* json, int server, struct json** response);

/**
 * Read the management JSON
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param compression The pointer to an integer that will store the compress method
 * @param json The JSON structure
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_read_json(SSL* ssl, int socket, uint8_t* compression, uint8_t* encryption, struct json** json);

/**
 * Write the management JSON
 * @param ssl The SSL connection
 * @param socket The socket descriptor
 * @param compression The compress method for wire protocol
 * @param encryption The encrypt method for wire protocol (None or *_GCM)
 * @param json The JSON structure
 * @return 0 upon success, otherwise 1
 */
int
pgagroal_management_write_json(SSL* ssl, int socket, uint8_t compression, uint8_t encryption, struct json* json);

#ifdef __cplusplus
}
#endif

#endif
