// SPDX-License-Identifier: GPL-2.0 OR LGPL-2.1 OR CDDL-1.0
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or https://opensource.org/licenses/CDDL-1.0.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/* Copyright (c) 2019-2026 Chilledheart  */

#ifndef YASS_CLIENT_H
#define YASS_CLIENT_H

#include "yass/config.h"

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/* clang-format off */

#define YASS_CLIENT_ABI_VERSION 3
#define YASS_CLIENT_ABI_STABLE  0

typedef void* yass_client_instance;

/*!
 *  \brief Construct an instance of YassClient.
 *
 *  return NULL if error occurs
 */
YASS_DLL yass_client_instance yass_client_instance_create();
/*!
 *  \brief Initialize specified instance of YassClient.
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *
 *  return non-zero if error occurs
 */
YASS_DLL int yass_client_instance_init(yass_client_instance instance);
/*!
 *  \brief Add server configuration to specified instance of YassClient (variant 1).
 *
 *  \param instance    specified instance (cannot be NULL).
 *  \param server_tag  the number to distinguish the server configuration
 *  \param proxy_uri   the URI format of upstream including username and password where server proxies network traffic to
 *  \param listen_uri  the URI format of downstream where server listens at locally
 *  \param listen_port if not NULL, the pointer will be assigned the real port where server listens
 *
 *  return non-zero if error occurs
 */
YASS_DLL int yass_client_instance_add_server_uri(yass_client_instance instance, int64_t server_tag, const char* proxy_uri,
                                                 const char* listen_uri, uint16_t* listen_port);

YASS_DLL int yass_client_instance_add_server_uri_v1(yass_client_instance instance, int64_t server_tag, const char* proxy_uri,
                                                    const char* listen_uri, uint16_t* listen_port,
                                                    char* remote_server_ips_cstr, size_t* remote_server_ips_cstr_len,
                                                    char* remote_server_ips_v4_cstr, size_t* remote_server_ips_v4_cstr_len,
                                                    char* remote_server_ips_v6_cstr, size_t* remote_server_ips_v6_cstr_len);
/*!
 *  \brief Add server configuration to specified instance of YassClient (variant 2).
 *
 *  \param instance                specified instance (cannot be NULL).
 *  \param server_tag              the number to distinguish the server configuration
 *  \param remote_host_name        the hostname of upstream where server proxies network traffic to, cannot be NULL
 *  \param remote_host_sni         the SNI to override hostname of upstream where server proxies network traffic to, can be NULL
 *  \param remote_port             the port number of upstream where server proxies network traffic to, cannot be zero
 *  \param remote_username         the username of upstream where server proxies network traffic to, can be NULL
 *  \param remote_password         the password of upstream where server proxies network traffic to, can be NULL
 *  \param remote_cipher           the cipher number form of upstream where server proxies network traffic to, cannot be invalid
 *  \param remote_padding_support  the padding support of upstream where server proxies network traffic to, only valid on YASS_CRYPTO_HTTP2
 *  \param local_host_name         the hostname of downstream where server listens at locally, cannot be NULL
 *  \param local_port              the port number of downstream where server listens at locally, cannot be zero
 *  \param redir_mode              the redir mode of downstream where server listens at locally, usually be false
 *  \param listen_port if not NULL, the pointer will be assigned the real port where server listens
 *
 *  return non-zero if error occurs
 */
YASS_DLL int yass_client_instance_add_server(yass_client_instance instance, int64_t server_tag, const char* remote_host_name,
                                             const char* remote_host_sni, uint16_t remote_port, const char* remote_username,
                                             const char* remote_password, int remote_cipher, bool remote_padding_support,
                                             const char* local_host_name, uint16_t local_port, bool redir_mode, uint16_t* listen_port);

YASS_DLL int yass_client_instance_add_server_v1(yass_client_instance instance, int64_t server_tag, const char* remote_host_name,
                                                const char* remote_host_sni, uint16_t remote_port, const char* remote_username,
                                                const char* remote_password, int remote_cipher, bool remote_padding_support,
                                                const char* local_host_name, uint16_t local_port, bool redir_mode, uint16_t* listen_port,
                                                char* remote_server_ips_cstr, size_t* remote_server_ips_cstr_len,
                                                char* remote_server_ips_v4_cstr, size_t* remote_server_ips_v4_cstr_len,
                                                char* remote_server_ips_v6_cstr, size_t* remote_server_ips_v6_cstr_len);
/*!
 *  \brief Run the internal loop to poll the request
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *
 *  block current thread, all configuration will be dropped after this call
 *
 *  return non-zero if error occurs
 */
YASS_DLL int yass_client_instance_run(yass_client_instance instance);
/*!
 *  \brief Count the number of current connections
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *
 *  thread-safe
 *
 *  return the number of current connections
 */
YASS_DLL int yass_client_instance_num_of_connections(yass_client_instance instance);
/*!
 *  \brief Shutdown Instance of YassClient Gracefully
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *
 *  thread-safe, all pending I/O will be handled
 *
 *  return non-zero if error occurs
 */
YASS_DLL int yass_client_instance_shutdown(yass_client_instance instance);
/*!
 *  \brief Stop Instance of YassClient Immediately
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *
 *  thread-safe, all pending I/O will be cancelled and discarded
 *
 *  return non-zero if error occurs
 */
YASS_DLL int yass_client_instance_cancel(yass_client_instance instance);
/*!
 *  \brief Destroy Instance of YassClient
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *
 *  not thread-safe, the YassClient instance will be invalidated after this call.
 */
YASS_DLL void yass_client_instance_destroy(yass_client_instance instance);
/*!
 *  \brief Get Last Error (Number) from the given instance of YassClient
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *
 *  thread-safe
 *
 *  return the error number when the error occurs last time
 */
YASS_DLL int yass_client_instance_get_last_error(yass_client_instance instance);
/*!
 *  \brief Get Last Error (String) from the given instance of YassClient
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *
 *  not thread-safe
 *
 *  return the pointer to internal buffer which renders the error message when the error occurs last time
 */
YASS_DLL const char* yass_client_instance_get_last_error_str(yass_client_instance instance);
/*!
 *  \brief Get Last Error (Number And String) from the given instance of YassClient
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *  \param strerrbuf the buffer pointer used to render the error message
 *  \param buf_len the maximum buffer length to render the error message
 *
 *  thread-safe
 *
 *  return the error number when the error occurs last time
 */
YASS_DLL int yass_client_instance_get_last_error_xsi_r(yass_client_instance instance, char* strerrbuf, size_t buflen);
/*!
 *  \brief Run a lightweight task inside the internal run loop
 *
 *  \param instance specified instance of YassClient (cannot be NULL).
 *  \param func     specified function pointer of task
 *  \param arg      specified function argument of task (opaque)
 *
 *  thread-safe, only valid when client internal run loop is running, aka yass_client_instance_run is called without quiting.
 *
 *  Please note it is not guarenteed that the task will be fired at last because the run loop might
 *  stop before the task. And the user must make sure the func including argument stay valid in
 *  the life-cycle of the run loop. Due to the above reasons, memory management of the task itself is
 *  not gurenteed. We might create a new api to post self-managed task or so-called closure in future,
 *  but that's a different story.
 *
 *  return non-zero if error occurs
 */
typedef void (*yass_client_task_func_t)(void*);
YASS_DLL int yass_client_instance_post_task(yass_client_instance instance, yass_client_task_func_t func, void* arg);

/* clang-format on */

#ifdef __cplusplus
}  // extern "C"
#endif

#endif  // YASS_CLIENT_H
