#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"

el_val_t tier_working(void);
el_val_t tier_episodic(void);
el_val_t tier_canonical(void);
el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags);
el_val_t mem_remember(el_val_t content, el_val_t tags);
el_val_t mem_recall(el_val_t query, el_val_t depth);
el_val_t mem_search(el_val_t query, el_val_t limit);
el_val_t mem_strengthen(el_val_t node_id);
el_val_t mem_tombstone(el_val_t node_id);
el_val_t mem_forget(el_val_t node_id);
el_val_t mem_consolidate(void);
el_val_t mem_save(el_val_t path);
el_val_t mem_load(el_val_t path);
el_val_t mem_boot_count_get(void);
el_val_t mem_boot_count_inc(void);
el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content);

el_val_t tier_working(void) {
  return EL_STR("Working");
  return 0;
}

el_val_t tier_episodic(void) {
  return EL_STR("Episodic");
  return 0;
}

el_val_t tier_canonical(void) {
  return EL_STR("Canonical");
  return 0;
}

el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags) {
  el_val_t id = engram_node_full(content, EL_STR("Memory"), label, el_from_float(0.5), el_from_float(0.5), el_from_float(0.8), EL_STR("Working"), tags);
  if (str_eq(id, EL_STR(""))) {
    println(el_str_concat(EL_STR("[memory] write rejected by engram (empty id): label="), label));
    return EL_STR("");
  }
  el_val_t readback = engram_get_node_json(id);
  if (str_eq(readback, EL_STR("")) || str_eq(readback, EL_STR("{}"))) {
    println(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] WRITE VERIFY FAILED: label="), label), EL_STR(" id=")), id), EL_STR(" \xe2\x80\x94 node absent after write")));
    return EL_STR("");
  }
  println(el_str_concat(el_str_concat(EL_STR("[memory] write verified: "), id), EL_STR(" ok")));
  return id;
  return 0;
}

el_val_t mem_remember(el_val_t content, el_val_t tags) {
  return mem_store(content, EL_STR("soul-memory"), tags);
  return 0;
}

el_val_t mem_recall(el_val_t query, el_val_t depth) {
  return engram_activate_json(query, depth);
  return 0;
}

el_val_t mem_search(el_val_t query, el_val_t limit) {
  return engram_search_json(query, limit);
  return 0;
}

el_val_t mem_strengthen(el_val_t node_id) {
  engram_strengthen(node_id);
  return 0;
}

el_val_t mem_tombstone(el_val_t node_id) {
  el_val_t tags = EL_STR("[\"Tombstone\",\"status:deleted\"]");
  el_val_t marker = engram_node_full(node_id, EL_STR("Tombstone"), el_str_concat(EL_STR("tombstone:"), node_id), el_from_float(0.01), el_from_float(0.01), el_from_float(1.0), EL_STR("Episodic"), tags);
  if (!str_eq(marker, EL_STR(""))) {
    engram_connect(marker, node_id, el_from_float(1.0), EL_STR("tombstones"));
  }
  return marker;
  return 0;
}

el_val_t mem_forget(el_val_t node_id) {
  el_val_t _marker = mem_tombstone(node_id);
  return 0;
}

el_val_t mem_consolidate(void) {
  el_val_t scanned = engram_node_count();
  el_val_t total_edges = engram_edge_count();
  el_val_t strengthened = 0;
  el_val_t wm_top = engram_wm_top_json(10);
  el_val_t wm_len = json_array_len(wm_top);
  el_val_t wi = 0;
  while (wi < wm_len) {
    el_val_t wm_node = json_array_get(wm_top, wi);
    el_val_t wm_id = json_get(wm_node, EL_STR("id"));
    if (!str_eq(wm_id, EL_STR(""))) {
      engram_strengthen(wm_id);
      strengthened = (strengthened + 1);
    }
    wi = (wi + 1);
  }
  el_val_t scan_result = engram_scan_nodes_json(50, 0);
  el_val_t scan_len = json_array_len(scan_result);
  el_val_t si = 0;
  while (si < scan_len) {
    el_val_t s_node = json_array_get(scan_result, si);
    el_val_t s_tier = json_get(s_node, EL_STR("tier"));
    el_val_t s_id = json_get(s_node, EL_STR("id"));
    if (str_eq(s_tier, EL_STR("Canonical")) && !str_eq(s_id, EL_STR(""))) {
      engram_strengthen(s_id);
      strengthened = (strengthened + 1);
    }
    si = (si + 1);
  }
  el_val_t total_nodes = engram_node_count();
  return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"scanned\":"), int_to_str(scanned)), EL_STR(",\"total_nodes\":")), int_to_str(total_nodes)), EL_STR(",\"total_edges\":")), int_to_str(total_edges)), EL_STR(",\"strengthened\":")), int_to_str(strengthened)), EL_STR("}"));
  return 0;
}

el_val_t mem_save(el_val_t path) {
  el_val_t saved = engram_save(path);
  if (saved == 0) {
    println(el_str_concat(el_str_concat(EL_STR("[memory] mem_save: engram_save failed for "), path), EL_STR(" \xe2\x80\x94 snapshot may be incomplete")));
  }
  return 0;
}

el_val_t mem_load(el_val_t path) {
  engram_load(path);
  return 0;
}

el_val_t mem_boot_count_get(void) {
  el_val_t results = engram_search_json(EL_STR("soul:boot_count"), 3);
  if (str_eq(results, EL_STR(""))) {
    return 0;
  }
  if (str_eq(results, EL_STR("[]"))) {
    return 0;
  }
  el_val_t node = json_array_get(results, 0);
  el_val_t content = json_get(node, EL_STR("content"));
  el_val_t prefix = EL_STR("soul:boot_count:");
  if (!str_starts_with(content, prefix)) {
    return 0;
  }
  el_val_t num_str = str_slice(content, str_len(prefix), str_len(content));
  return str_to_int(num_str);
  return 0;
}

el_val_t mem_boot_count_inc(void) {
  el_val_t current = mem_boot_count_get();
  el_val_t next = (current + 1);
  el_val_t old_results = engram_search_json(EL_STR("soul:boot_count"), 50);
  if (!str_eq(old_results, EL_STR("")) && !str_eq(old_results, EL_STR("[]"))) {
    el_val_t old_len = json_array_len(old_results);
    el_val_t oi = 0;
    while (oi < old_len) {
      el_val_t old_node = json_array_get(old_results, oi);
      el_val_t old_id = json_get(old_node, EL_STR("id"));
      if (!str_eq(old_id, EL_STR(""))) {
        engram_forget(old_id);
      }
      oi = (oi + 1);
    }
  }
  el_val_t content = el_str_concat(EL_STR("soul:boot_count:"), int_to_str(next));
  el_val_t tags = EL_STR("[\"soul-meta\",\"boot-counter\"]");
  el_val_t boot_node_id = engram_node_full(content, EL_STR("Memory"), EL_STR("soul:boot_count"), el_from_float(0.55), el_from_float(0.2), el_from_float(1.0), EL_STR("Working"), tags);
  if (str_eq(boot_node_id, EL_STR(""))) {
    println(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: write rejected (empty id) \xe2\x80\x94 boot counter node lost (count="), int_to_str(next)), EL_STR(")")));
    return next;
  }
  el_val_t boot_readback = engram_get_node_json(boot_node_id);
  if (str_eq(boot_readback, EL_STR("")) || str_eq(boot_readback, EL_STR("{}"))) {
    println(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: WRITE VERIFY FAILED id="), boot_node_id), EL_STR(" count=")), int_to_str(next)));
  }
  el_val_t wb_url = env(EL_STR("ENGRAM_URL"));
  el_val_t wb_key = env(EL_STR("ENGRAM_API_KEY"));
  if (!str_eq(wb_url, EL_STR("")) && !str_eq(wb_key, EL_STR(""))) {
    el_val_t auth_body = el_str_concat(el_str_concat(EL_STR("{\"_auth\":\""), json_safe(wb_key)), EL_STR("\"}"));
    el_val_t srv_old = http_get(el_str_concat(wb_url, EL_STR("/api/search?q=soul:boot_count&limit=20")));
    if (!str_eq(srv_old, EL_STR("")) && !str_eq(srv_old, EL_STR("[]"))) {
      el_val_t srv_len = json_array_len(srv_old);
      el_val_t si = 0;
      while (si < srv_len) {
        el_val_t srv_node = json_array_get(srv_old, si);
        el_val_t srv_content = json_get(srv_node, EL_STR("content"));
        if (str_starts_with(srv_content, EL_STR("soul:boot_count:"))) {
          el_val_t srv_id = json_get(srv_node, EL_STR("id"));
          if (!str_eq(srv_id, EL_STR(""))) {
            http_delete_json(el_str_concat(el_str_concat(wb_url, EL_STR("/api/nodes/")), srv_id), auth_body);
          }
        }
        si = (si + 1);
      }
    }
    el_val_t wb_body = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"content\":\""), content), EL_STR("\",\"node_type\":\"Memory\",\"label\":\"soul:boot_count\",\"salience\":0.55,\"importance\":0.2,\"tier\":\"Working\",\"tags\":\"[\\\"soul-meta\\\",\\\"boot-counter\\\"]\",\"_auth\":\"")), json_safe(wb_key)), EL_STR("\"}"));
    el_val_t wb_resp = http_post_json(el_str_concat(wb_url, EL_STR("/api/nodes")), wb_body);
    if (str_contains(wb_resp, EL_STR("\"error\""))) {
      println(el_str_concat(EL_STR("[memory] mem_boot_count_inc: HTTP write-back failed (count in-memory only): "), wb_resp));
    }
  }
  return next;
  return 0;
}

el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content) {
  el_val_t boot = mem_boot_count_get();
  el_val_t ts = time_now();
  el_val_t safe_trigger = str_replace(trigger, EL_STR("\""), EL_STR("'"));
  el_val_t safe_content = str_replace(content, EL_STR("\""), EL_STR("'"));
  el_val_t payload = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"trigger\":\""), safe_trigger), EL_STR("\"")), EL_STR(",\"kind\":\"")), kind), EL_STR("\"")), EL_STR(",\"content\":\"")), safe_content), EL_STR("\"")), EL_STR(",\"boot\":")), int_to_str(boot)), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
  el_val_t tags = EL_STR("[\"internal-state\",\"pre-reasoning\",\"InternalStateEvent\"]");
  el_val_t event_id = engram_node_full(payload, EL_STR("InternalStateEvent"), el_str_concat(EL_STR("state-event:"), kind), el_from_float(0.85), el_from_float(0.8), el_from_float(0.9), EL_STR("Episodic"), tags);
  if (str_eq(event_id, EL_STR(""))) {
    println(el_str_concat(EL_STR("[memory] mem_emit_state_event: write rejected (empty id): kind="), kind));
  }
  return event_id;
  return 0;
}

