// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// C ABI header file for the tfmtok library

#pragma once

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

#if defined(__CYGWIN__) || defined(__MINGW32__)
#define TFM_API_CALL __stdcall
#elif defined(_WIN32)
#define TFM_API_CALL _stdcall
#define TFM_MUST_USE_RESULT
#elif __APPLE__
#define TFM_API_CALL
// To make symbols visible on macOS/iOS
#define TFM_MUST_USE_RESULT __attribute__((warn_unused_result))
#else
#define TFM_API_CALL
#define TFM_MUST_USE_RESULT
#endif

typedef enum {
  kTfmOK = 0,
  kTfmErrorInvalidArgument = 1,
  kTfmErrorOutOfMemory = 2,
  kTfmErrorInvalidFile = 3,
  kTfmErrorNotFound = 4,
  kTfmErrorAlreadyExists = 5,
  kTfmErrorOutOfRange = 6,
  kTfmErrorUnimplemented = 7,
  kTfmErrorInternal = 8,
  kTfmErrorUnknown = 1000
} tfmError_t;

typedef enum {
  kTfmKindUnknown = 0,

  kTfmKindBegin = 0x7788, // starting from a number to help validate the object
  kTfmKindTokenizer = kTfmKindBegin,
  kTfmKindStringArray = 0x7789,
  kTfmKindTokenId2DArray = 0x778A,
  kTfmKindDetokenizerCache = 0x778B,
  kTfmKindEnd = 0x7999
} tfmObjectKind_t;


// all object managed by the library should be 'derived' from this struct
// which eventually will be released by TfmDispose if C++, or TFM_DISPOSE if C
typedef struct {
  int tfm_kind_;
}TfmObject;

const int API_VERSION = 1;

// typedefs to create/dispose function flood, and to make the API more C++ friendly with less casting
typedef TfmObject TfmTokenizer;
typedef TfmObject TfmStringArray;
typedef TfmObject TfmTokenId2DArray;
typedef TfmObject TfmDetokenizerCache;

// C, instead of C++ doesn't cast automatically,
// so we need to use a macro to cast the object to the correct type
#define TFM_DISPOSE(obj) TfmDispose((TfmObject**)&obj)

typedef uint32_t tfmTokenId_t;

#ifdef __cplusplus
extern "C" {
#endif

/** \brief Get the current C ABI version of this library
 *
 * \snippet{doc} snippets.dox int Return Value
 */
int TFM_API_CALL TfmGetAPIVersion();

/** \brief Get the last error message generated by the library
 *
 * \param message Pointer to store the last error message
 * \return Pointer to the last error message
 */
const char* TFM_API_CALL TfmGetLastErrorMessage();

/** \brief Create a new object of the specified kind
 *
 * \param kind The kind of object to create
 * \param object Pointer to store the created object
 * \param ... Additional arguments based on the kind of object
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmCreate(tfmObjectKind_t kind, TfmObject** object, ...);

/** \brief Dispose the specified object
 *
 * \param object Pointer to the object to dispose
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmDispose(TfmObject** object);

/** \brief Create a tokenizer object with the specified tokenizer path
 *
 * \param tokenizer Pointer to store the created tokenizer object
 * \param tokenizer_path The path to the tokenizer
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmCreateTokenizer(TfmTokenizer** tokenizer, const char* tokenizer_path);

/** \brief Tokenize the input using the specified tokenizer
 *
 * \param tokenizer Pointer to the tokenizer object
 * \param input Array of input strings
 * \param batch_size Number of input strings in the batch
 * \param output Pointer to store the tokenized result
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmTokenize(const TfmTokenizer* tokenizer, const char* input[], size_t batch_size, TfmTokenId2DArray** output);

/** \brief Detokenize the input using the specified tokenizer
 *
 * \param tokenizer Pointer to the tokenizer object
 * \param input Pointer to the input token IDs
 * \param output Pointer to store the detokenized result
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmDetokenize(const TfmTokenizer* tokenizer, const TfmTokenId2DArray* input, TfmStringArray** output);

/** \brief Detokenize the input using the specified tokenizer (1D version)
 *
 * \param tokenizer Pointer to the tokenizer object
 * \param input Pointer to the input token IDs
 * \param len Length of the input token IDs array
 * \param output Pointer to store the detokenized result
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmDetokenize1D(const TfmTokenizer* tokenizer, const tfmTokenId_t* input, size_t len, TfmStringArray** output);

/** \brief Detokenize the input using the specified tokenizer with caching
 *
 * \param tokenizer Pointer to the tokenizer object
 * \param cache Pointer to the detokenizer cache
 * \param next_id Next token ID to detokenize
 * \param text_out Pointer to store the detokenized text
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmDetokenizeCached(const TfmTokenizer* tokenizer, TfmDetokenizerCache* cache, tfmTokenId_t next_id, const char** text_out);

/** \brief Get the length of the string array
 *
 * \param string_array Pointer to the string array
 * \param length Pointer to store the length of the string array
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmStringArrayGetBatch(const TfmStringArray* string_array, size_t* length);

/** \brief Get the item at the specified index from the string array
 *
 * \param string_array Pointer to the string array
 * \param index Index of the item to retrieve
 * \param item Pointer to store the retrieved item
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmStringArrayGetItem(const TfmStringArray* string_array, size_t index, const char** item);

/** \brief Get the batch size of the token ID 2D array
 *
 * \param token_id_2d_array Pointer to the token ID 2D array
 * \param length Pointer to store the batch size
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmTokenId2DArrayGetBatch(const TfmTokenId2DArray* token_id_2d_array, size_t* length);

/** \brief Get the item at the specified index from the token ID 2D array
 *
 * \param token_id_2d_array Pointer to the token ID 2D array
 * \param index Index of the item to retrieve
 * \param item Pointer to store the retrieved item
 * \param length Pointer to store the length of the item
 * \return Error code indicating the success or failure of the operation
 */
tfmError_t TFM_API_CALL TfmTokenId2DArrayGetItem(const TfmTokenId2DArray* token_id_2d_array, size_t index, const tfmTokenId_t** item, size_t* length);

#ifdef __cplusplus
}
#endif
