//
//  install.h
//  humand
//
//  Created by Oleksandr Shumihin on 02/04/2026.
//  Copyright © 2026 Humand. All rights reserved.
//
#pragma once

#include "jsi/jsi.h"
#include "native-logger.h"

constexpr static size_t ULID_SIZE = 26;

namespace humand::native_logger {
inline void install(jsi::Runtime &rt) {

  jsi::Object logger(rt);

  auto native_state = std::make_shared<FileLogger>();

  logger.setNativeState(rt, native_state);

  auto init = jsi::Function::createFromHostFunction(
      rt, jsi::PropNameID::forAscii(rt, "init"), 2,
      [native_state](jsi::Runtime &rt, const jsi::Value &thisValue,
                     const jsi::Value *arguments, size_t count) -> jsi::Value {
        if (count < 2 || !arguments[0].isString() || !arguments[1].isNumber())
            [[unlikely]] {
          return false;
        }

        const auto log_file_path = arguments[0].asString(rt).utf8(rt);
        const size_t requested_bytes =
            static_cast<size_t>(arguments[1].asNumber());

        return native_state->init(log_file_path, requested_bytes);
      });

  auto is_empty = jsi::Function::createFromHostFunction(
      rt, jsi::PropNameID::forAscii(rt, "is_empty"), 0,
      [native_state](jsi::Runtime &rt, const jsi::Value &thisValue,
                     const jsi::Value *arguments, size_t count) -> jsi::Value {
        return jsi::Value(native_state->is_empty());
      });

  auto clear = jsi::Function::createFromHostFunction(
      rt, jsi::PropNameID::forAscii(rt, "clear"), 0,
      [native_state](jsi::Runtime &rt, const jsi::Value &thisValue,
                     const jsi::Value *arguments, size_t count) -> jsi::Value {
        native_state->clear();

        return jsi::Value::undefined();
      });

  auto start_buffering = jsi::Function::createFromHostFunction(
      rt, jsi::PropNameID::forAscii(rt, "start_buffering"), 0,
      [native_state](jsi::Runtime &rt, const jsi::Value &thisValue,
                     const jsi::Value *arguments, size_t count) -> jsi::Value {
        native_state->start_buffering();
        return jsi::Value::undefined();
      });

  auto stop_buffering_and_flush = jsi::Function::createFromHostFunction(
      rt, jsi::PropNameID::forAscii(rt, "stop_buffering_and_flush"), 0,
      [native_state](jsi::Runtime &rt, const jsi::Value &thisValue,
                     const jsi::Value *arguments, size_t count) -> jsi::Value {
        native_state->stop_buffering_and_flush();
        return jsi::Value::undefined();
      });

  auto get_meta = jsi::Function::createFromHostFunction(
      rt, jsi::PropNameID::forAscii(rt, "get_meta"), 0,
      [native_state](jsi::Runtime &rt, const jsi::Value &thisValue,
                     const jsi::Value *arguments, size_t count) -> jsi::Value {
        jsi::Object js_meta(rt);

        Meta meta = native_state->get_meta();

        js_meta.setProperty(
            rt, "cursor",
            static_cast<double>(meta.cursor)); // next write position

        js_meta.setProperty(rt, "capacity",
                            static_cast<double>(meta.max_lines));

        return js_meta;
      });

  auto append = jsi::Function::createFromHostFunction(
      rt, jsi::PropNameID::forAscii(rt, "append"), 2,
      [native_state](jsi::Runtime &rt, const jsi::Value &thisValue,
                     const jsi::Value *arguments, size_t count) -> jsi::Value {
        if (count < 2 || !arguments[0].isString() || !arguments[1].isNumber())
            [[unlikely]] {
          return false;
        }

        char ulid_buf[ULID_SIZE];
        size_t written = 0;

        auto cb = [&written, &ulid_buf](bool ascii, const void *data,
                                        size_t num) {
          if (!ascii || written + num > ULID_SIZE) [[unlikely]] {
            return;
          }

          std::memcpy(ulid_buf + written, data, num);
          written += num;
        };

        arguments[0].asString(rt).getStringData(rt, cb);

        if (written != ULID_SIZE) [[unlikely]] {
          return false;
        }

        const auto status = static_cast<int>(
            arguments[1].asNumber()); // 0 - Arrived; 1 - Saved;

        return native_state->append(std::string_view{ulid_buf, ULID_SIZE},
                                    status);
      });

  logger.setProperty(rt, "init", std::move(init));
  logger.setProperty(rt, "append", std::move(append));
  logger.setProperty(rt, "get_meta", std::move(get_meta));
  logger.setProperty(rt, "is_empty", std::move(is_empty));
  logger.setProperty(rt, "clear", std::move(clear));
  logger.setProperty(rt, "start_buffering", std::move(start_buffering));
  logger.setProperty(rt, "stop_buffering_and_flush",
                     std::move(stop_buffering_and_flush));

  rt.global().setProperty(rt, "__NativeFileLogger", std::move(logger));
};
} // namespace humand::native_logger
