#include "qjs_kim.h"
#include "qjs_blob.h"
#include "jsffi.h"
#include <string.h>
#include <stdlib.h>

#define KIM_IMPLEMENTATION
#include "kim.h"

JSC_CCALL(kim_encode,
  const char *utf8_str = JS_ToCString(js, argv[0]);
  if (!utf8_str) return JS_EXCEPTION;
  
  // Count runes to estimate kim buffer size
  int rune_count = utf8_count(utf8_str);
  
  // Allocate kim buffer (worst case: 5 bytes per rune)
  size_t kim_size = rune_count * 5;
  char *kim_buffer = malloc(kim_size);
  char *kim_ptr = kim_buffer;
  
  // Encode utf8 to kim
  long long runes_encoded;
  utf8_to_kim(&utf8_str, &kim_ptr, &runes_encoded);
  
  // Calculate actual size used
  size_t actual_size = kim_ptr - kim_buffer;
  
  // Create blob with the encoded data
  ret = js_new_blob_stoned_copy(js, kim_buffer, actual_size);
  
  free(kim_buffer);
  JS_FreeCString(js, utf8_str);
)

JSC_CCALL(kim_decode,
  size_t kim_len;
  void *kim_data = js_get_blob_data(js, &kim_len, argv[0]);
  if (!kim_data) return JS_ThrowTypeError(js, "Expected blob");
  
  // Allocate UTF-8 buffer (worst case: 4 bytes per kim byte)
  size_t utf8_size = kim_len * 4;
  char *utf8_buffer = malloc(utf8_size + 1); // +1 for null terminator
  char *utf8_ptr = utf8_buffer;
  
  // Copy kim data since kim_to_utf8 modifies the pointer
  char *kim_copy = malloc(kim_len);
  memcpy(kim_copy, kim_data, kim_len);
  char *kim_ptr = kim_copy;
  
  // Count runes in kim data
  int rune_count = 0;
  char *temp_ptr = kim_copy;
  while (temp_ptr < kim_copy + kim_len) {
    decode_kim(&temp_ptr);
    rune_count++;
  }
  
  // Reset pointer and decode
  kim_ptr = kim_copy;
  kim_to_utf8(&kim_ptr, &utf8_ptr, rune_count);
  
  // Null terminate
  *utf8_ptr = '\0';
  
  ret = JS_NewString(js, utf8_buffer);
  
  free(utf8_buffer);
  free(kim_copy);
)

static const JSCFunctionListEntry js_kim_funcs[] = {
  MIST_FUNC_DEF(kim, encode, 1),
  MIST_FUNC_DEF(kim, decode, 1),
};

JSValue js_kim_use(JSContext *js)
{
  JSValue mod = JS_NewObject(js);
  JS_SetPropertyFunctionList(js, mod, js_kim_funcs, countof(js_kim_funcs));
  return mod;
}