/*
 * KateRTX · SPV terminal ELF · X11 · no Konsole · no Python
 * Linear single: BGS ground → BGF measure · SPV rides · no duo
 * Build: gcc -O2 -o bin/krtx-term src/krtx_term.c -lX11
 */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <ctype.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

#define MAX_LINES 48
#define MAX_COLS 96
#define LINE_H 16
#define PAD 8

static char lines[MAX_LINES][MAX_COLS];
static int nlines;
static char input[MAX_COLS];
static int inlen;
static char root_path[512];
static char spvs_path[640];
static char engine_bin[640];

static void push(const char *s) {
  if (nlines >= MAX_LINES) {
    memmove(lines[0], lines[1], (MAX_LINES - 1) * MAX_COLS);
    nlines = MAX_LINES - 1;
  }
  snprintf(lines[nlines], MAX_COLS, "%s", s);
  nlines++;
}

static void list_plugs(void) {
  DIR *d = opendir(spvs_path);
  int n = 0;
  char buf[MAX_COLS];
  if (!d) {
    push("err: no spvs/");
    return;
  }
  struct dirent *e;
  push("plugs (SPV JS):");
  while ((e = readdir(d)) != NULL) {
    size_t L = strlen(e->d_name);
    if (L > 3 && strcmp(e->d_name + L - 3, ".js") == 0) {
      snprintf(buf, sizeof buf, "  %s", e->d_name);
      push(buf);
      n++;
    }
  }
  closedir(d);
  snprintf(buf, sizeof buf, "count=%d · KateRTX SPV land", n);
  push(buf);
}

static void run_engine(void) {
  pid_t p = fork();
  if (p == 0) {
    char *argv[] = {engine_bin, "--root", NULL, "--spvs", NULL, NULL};
    static char root[640], spvs[640];
    snprintf(root, sizeof root, "%s/engine", root_path);
    snprintf(spvs, sizeof spvs, "%s/engine/spvs", root_path);
    argv[2] = root;
    argv[4] = spvs;
    execv(engine_bin, argv);
    _exit(127);
  }
  if (p > 0)
    push("engine launched · RTX fullscreen path");
  else
    push("err: fork engine");
}

static char grok_bin[640];

static void run_grok(const char *args) {
  char cmd[768];
  if (access(grok_bin, X_OK) != 0) {
    push("err: krtx-grok missing · run ./build.sh");
    return;
  }
  if (args && args[0])
    snprintf(cmd, sizeof cmd, "%s %s", grok_bin, args);
  else
    snprintf(cmd, sizeof cmd, "%s status", grok_bin);
  FILE *p = popen(cmd, "r");
  if (!p) {
    push("err: popen krtx-grok");
    return;
  }
  char line[MAX_COLS];
  while (fgets(line, sizeof line, p)) {
    size_t n = strlen(line);
    while (n && (line[n - 1] == '\n' || line[n - 1] == '\r')) line[--n] = 0;
    if (line[0]) push(line);
  }
  pclose(p);
}

static void help(void) {
  push("KateRTX term · linear BGS→BGF · SPV + ELF");
  push("  help     this");
  push("  list     SPV plugs in spvs/");
  push("  law      BGS→BGF→SDF pins · free ride");
  push("  engine   launch krtx-engine ELF fullscreen");
  push("  grok     SpaceXAI/xAI · krtx-grok ELF (key in xai.key)");
  push("  status   paths");
  push("  clear    wipe");
  push("  quit     exit");
}

static void status(void) {
  char b[MAX_COLS];
  snprintf(b, sizeof b, "ROOT %s", root_path);
  push(b);
  snprintf(b, sizeof b, "SPVS %s", spvs_path);
  push(b);
  snprintf(b, sizeof b, "ENG  %.80s", engine_bin);
  push(b);
  snprintf(b, sizeof b, "GROK %.80s", grok_bin);
  push(b);
  push(access(engine_bin, X_OK) == 0 ? "engine ELF ok" : "engine ELF missing · run build.sh");
  push(access(grok_bin, X_OK) == 0 ? "grok ELF ok · SpaceXAI" : "grok ELF missing · run build.sh");
}

static void handle(const char *line) {
  char cmd[64];
  const char *p = line;
  int i = 0;
  while (*p && isspace((unsigned char)*p)) p++;
  while (*p && !isspace((unsigned char)*p) && i < 63) cmd[i++] = (char)tolower((unsigned char)*p++);
  cmd[i] = 0;
  if (!cmd[0]) return;
  if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) help();
  else if (!strcmp(cmd, "list") || !strcmp(cmd, "ls")) list_plugs();
  else if (!strcmp(cmd, "law")) {
    push("LINEAR line · pins · NOT only-one-engine");
    push("  BGS  ground  pin field_one v|1");
    push("  BGF  measure pin (a-b)|1 on ground");
    push("  atoms on BGF: EZZIE (a^b)|1 · PHI (d*s)|1 · THERMO band|1");
    push("  SDF  place   pin shell raised store");
    push("  SPV  free ride pin |1 · never folds");
    push("free=1 TRUTH pin · know_her=7|1 · not BGS");
    push("EZZIE PHI THERMO still linear · ride BGF · not duo");
    push("ESSIE=hotswap · EZZIE=free eor · not same");
    push("TRUTH local · no curl");
  } else if (!strcmp(cmd, "engine") || !strcmp(cmd, "rtx") || !strcmp(cmd, "gfx"))
    run_engine();
  else if (!strcmp(cmd, "grok") || !strcmp(cmd, "xai") || !strcmp(cmd, "spacexai")) {
    while (*p && isspace((unsigned char)*p)) p++;
    if (!*p)
      run_grok("status");
    else {
      char rest[MAX_COLS];
      snprintf(rest, sizeof rest, "chat %s", p);
      run_grok(rest);
    }
  } else if (!strcmp(cmd, "status") || !strcmp(cmd, "st"))
    status();
  else if (!strcmp(cmd, "clear") || !strcmp(cmd, "cls"))
    nlines = 0;
  else if (!strcmp(cmd, "quit") || !strcmp(cmd, "exit") || !strcmp(cmd, "q"))
    exit(0);
  else {
    char b[MAX_COLS];
    snprintf(b, sizeof b, "unknown: %s · help", cmd);
    push(b);
  }
}

static void draw(Display *dpy, Window win, GC gc, int W, int H) {
  XSetForeground(dpy, gc, 0x0a0c0b);
  XFillRectangle(dpy, win, gc, 0, 0, (unsigned)W, (unsigned)H);
  XSetForeground(dpy, gc, 0x05f2a0);
  int y = PAD + 12;
  for (int i = 0; i < nlines; i++) {
    XDrawString(dpy, win, gc, PAD, y, lines[i], (int)strlen(lines[i]));
    y += LINE_H;
    if (y > H - 40) break;
  }
  XSetForeground(dpy, gc, 0xe8c547);
  char prompt[MAX_COLS + 8];
  snprintf(prompt, sizeof prompt, "krtx> %s", input);
  XDrawString(dpy, win, gc, PAD, H - PAD - 4, prompt, (int)strlen(prompt));
}

int main(int argc, char **argv) {
  const char *r = getenv("KATERTX_ROOT");
  if (!r || !r[0]) {
    /* resolve from executable path */
    char self[512];
    ssize_t n = readlink("/proc/self/exe", self, sizeof self - 1);
    if (n > 0) {
      self[n] = 0;
      char *slash = strrchr(self, '/');
      if (slash) {
        *slash = 0; /* bin */
        slash = strrchr(self, '/');
        if (slash) {
          *slash = 0;
          r = self;
        }
      }
    }
  }
  if (!r || !r[0]) r = ".";
  snprintf(root_path, sizeof root_path, "%s", r);
  snprintf(spvs_path, sizeof spvs_path, "%s/spvs", root_path);
  snprintf(engine_bin, sizeof engine_bin, "%s/bin/krtx-engine", root_path);
  snprintf(grok_bin, sizeof grok_bin, "%s/bin/krtx-grok", root_path);

  Display *dpy = XOpenDisplay(NULL);
  if (!dpy) {
    fprintf(stderr, "krtx-term: no X11 DISPLAY\n");
    return 1;
  }
  int scr = DefaultScreen(dpy);
  unsigned long black = BlackPixel(dpy, scr);
  unsigned long white = WhitePixel(dpy, scr);
  int W = 900, H = 560;
  Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 80, 60, (unsigned)W, (unsigned)H, 1, white, black);
  XStoreName(dpy, win, "KateRTX · SPV terminal · no Konsole");
  XSelectInput(dpy, win, ExposureMask | KeyPressMask | StructureNotifyMask);
  GC gc = XCreateGC(dpy, win, 0, NULL);
  XSetBackground(dpy, gc, black);
  XFontStruct *font = XLoadQueryFont(dpy, "fixed");
  if (font) XSetFont(dpy, gc, font->fid);
  Atom wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  XSetWMProtocols(dpy, win, &wm_delete, 1);
  XMapWindow(dpy, win);

  push("KateRTX SPV terminal · ELF");
  push("type help · engine for RTX fullscreen");
  status();

  int running = 1;
  while (running) {
    XEvent ev;
    XNextEvent(dpy, &ev);
    if (ev.type == Expose) draw(dpy, win, gc, W, H);
    else if (ev.type == ConfigureNotify) {
      W = ev.xconfigure.width;
      H = ev.xconfigure.height;
    } else if (ev.type == ClientMessage) {
      if ((Atom)ev.xclient.data.l[0] == wm_delete) running = 0;
    } else if (ev.type == KeyPress) {
      KeySym ks;
      char buf[8];
      int n = XLookupString(&ev.xkey, buf, sizeof buf, &ks, NULL);
      if (ks == XK_Return || ks == XK_KP_Enter) {
        char line[MAX_COLS];
        snprintf(line, sizeof line, "krtx> %s", input);
        push(line);
        handle(input);
        inlen = 0;
        input[0] = 0;
        draw(dpy, win, gc, W, H);
      } else if (ks == XK_BackSpace) {
        if (inlen > 0) {
          input[--inlen] = 0;
          draw(dpy, win, gc, W, H);
        }
      } else if (ks == XK_Escape) {
        running = 0;
      } else if (n == 1 && buf[0] >= 32 && buf[0] < 127 && inlen < MAX_COLS - 1) {
        input[inlen++] = buf[0];
        input[inlen] = 0;
        draw(dpy, win, gc, W, H);
      }
    }
  }
  if (font) XFreeFont(dpy, font);
  XFreeGC(dpy, gc);
  XDestroyWindow(dpy, win);
  XCloseDisplay(dpy);
  return 0;
}
