#ifndef __VEREIGN_VEREIGN_H
#define __VEREIGN_VEREIGN_H

#ifdef _WIN32
  #ifdef WIN_EXPORT
    #define PUBLIC_API __declspec(dllexport)
  #else
    #define PUBLIC_API __declspec(dllimport)
  #endif
#else
  #define PUBLIC_API
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Error codes.
 */
enum vereign_error_code {
  VEREIGN_ERR_INTERNAL = 1,
  VEREIGN_ERR_GRPC_BIND_FAILED = 2
};

/**
 * Error object used for the error handling of the APIs.
 *
 * The error has a code and error message, which can be obtained by using the corresponding
 * methods ...
 */
typedef struct vereign_error vereign_error;

/**
 * Destroys ::vereign_error object.
 *
 * Error objects are created by the API calls as result of failures.
 *
 * It is safe to call it with null err.
 *
 * @param err The error to destroy.
 */
PUBLIC_API void vereign_error_free(vereign_error* err);

/**
 * Returns error object's code.
 *
 * @param err The error object.
 * @returns the error code.
 */
PUBLIC_API int vereign_error_code(vereign_error* err);

/**
 * Returns error object's message.
 *
 * @param err The error object.
 * @returns the error message.
 */
PUBLIC_API const char* vereign_error_message(vereign_error* err);

/**
 * Provides the gRPC API services.
 *
 * The object is created with ::vereign_service_start method, and shutdown with
 * ::vereign_service_shutdown.
 *
 * All object's methods are named with prefix `vereign_service_`.
 */
typedef struct vereign_service vereign_service;

// FIXME: generate SSL keys for gRPC communication.
/**
 * Creates ::vereign_service object and starts the gRPC API.
 *
 * The returned ::vereign_service object must be destroyed with ::vereign_service_shutdown method.
 * After successful start, the gRPC bind port can be retrieved with the
 * ::vereign_service_selected_port method. This is useful if the `listen_address` is in the form
 * "<host>:" (for example "localhost:"), in which case the port is not provided by the user but
 * from the OS.
 *
 * When the gRPC server cannot bind, `err` will have code VEREIGN_ERR_GRPC_BIND_FAILED.
 * Any other failures will set `err` with code VEREIGN_ERR_INTERNAL.
 *
 * **NOTE: On failure the `err` object must be freed with vereign_error_free method.**
 *
 * @param listen_address gRPC listen address, for example "localhost:".
 * @param vereign_host Vereign restapi host.
 * @param vereign_port Vereign restapi port - https, 443...
 * @param storage_path Full path to directory where the storage files will stay.
 *    If the `storage_path` is `nullptr`, a default will be used. Under linux this default is
 *    `$HOME/vereign`, and under windows it is `C:\Users\<user>\AppData\Local\vereign`.
 *
 * @param err On failure err is initialized with the reason of the failure,
 *    otherwise err is set to nullptr.
 * @returns vereign_service object if the gRPC is up and running, otherwise returns nullptr.
 */
PUBLIC_API vereign_service* vereign_service_start(
  const char* listen_address,
  const char* vereign_host,
  const char* vereign_port,
  const char* storage_path,
  vereign_error** err
);

/**
 * Retruns the port number selected by the gRPC server of the service.
 *
 * Must be called after the service is created with ::vereign_service_start, and before
 * it is destroyed with ::vereign_service_shutdown.
 *
 * @returns the port number selected by the gRPC server of the service.
 */
PUBLIC_API int vereign_service_selected_port(vereign_service* service);

/**
 * Stops and destroys the vereign service.
 *
 * It is safe to call with null `service`.
 *
 * @param service The object returned by the ::vereign_service_start function.
 */
PUBLIC_API void vereign_service_shutdown(vereign_service* service);

#ifdef __cplusplus
};
#endif

#endif // __VEREIGN_VEREIGN_H