#include "cell.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 blob (worst case: 5 bytes per rune)
  size_t kim_size = rune_count * 5;
  void *out;
  ret = js_new_blob_alloc(js, kim_size, &out);
  if (JS_IsException(ret)) { JS_FreeCString(js, utf8_str); return ret; }

  // Encode utf8 to kim directly into blob
  char *kim_ptr = (char *)out;
  long long runes_encoded;
  utf8_to_kim(&utf8_str, &kim_ptr, &runes_encoded);

  // Stone with actual size used
  size_t actual_size = kim_ptr - (char *)out;
  js_blob_stone(ret, actual_size);

  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 == (void *)-1) return JS_EXCEPTION;
  if (!kim_data) return JS_NewString(js, "");
  
  // 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_core_internal_kim_use(JSContext *js)
{
  JS_FRAME(js);
  JS_ROOT(mod, JS_NewObject(js));
  JS_SetPropertyFunctionList(js, mod.val, js_kim_funcs, countof(js_kim_funcs));
  JS_RETURN(mod.val);
}