// ============================================================
// Olive Garden — interactive terminal window
// Exposes TerminalContent to window
// ============================================================

const FS = {
  '~': ['about.txt', 'work/', 'travel/', 'writing/', 'hobbies/', 'plants/', 'now.md', 'README.md'],
  '~/work': ['genai-hub.md', 'esg-analytics.md', 'carbon-automation.md', 'rag-eval-toolkit.md'],
  '~/travel': ['alps.jpg', 'porto.jpg', 'harz.jpg', 'jeju.jpg', 'berlin.jpg', 'zurich.jpg'],
  '~/writing': ['agentic-needs-humans.md', 'rag-eval-honestly.md', 'poc-to-platform.md', 'n8n-recipes.md'],
  '~/hobbies': ['crochet/', 'paint/', 'hike/', 'plants/'],
  '~/plants': ['monstera.md', 'basil.md', 'coriander-try-4.md'],
};

const FILES = {
  'about.txt': 'AI Automation engineer. Hamburg + Zürich. Curious doer.\nAsking why & what\'s the value before what.',
  'README.md': '# jj.dev\nthis is a desktop. drag windows. click the sidebar. try `help`.',
  'now.md':    '● joining [company], zürich, aug 2026.\n— shipping rag-eval toolkit v0.3 next week.\n— writing about agentic eval.\n— attempting coriander again.',
  'monstera.md':  'big. healthy. +1 leaf this month.',
  'basil.md':     'overgrown. pesto incoming.',
  'coriander-try-4.md': 'try 4 of 4. fingers crossed.',
};

const HELP_LINES = [
  ['help',     'show this list'],
  ['ls [dir]', 'list directory contents'],
  ['cd <dir>', 'change directory'],
  ['cat <f>',  'read a file'],
  ['whoami',   'short bio'],
  ['now',      'current status'],
  ['open <app>', 'open a window — about · work · photos · writing · hobbies · contact'],
  ['donut',    'ascii torus (full-screen)'],
  ['stack',    'tools i build with'],
  ['hello',    '👋'],
  ['clear',    'clear screen'],
];

function TerminalContent({api}){
  const [cwd, setCwd] = React.useState('~');
  const [lines, setLines] = React.useState([
    { kind:'ok',  text:'jj.dev terminal · zsh-ish · v0.4' },
    { kind:'dim', text:'type `help` for commands · `donut` for a ride' },
    { kind:'spacer' },
  ]);
  const [input, setInput] = React.useState('');
  const [history, setHistory] = React.useState([]);
  const [histIdx, setHistIdx] = React.useState(-1);
  const scrollRef = React.useRef(null);
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [lines]);

  // Autofocus input when terminal is rendered
  React.useEffect(() => {
    const id = setTimeout(() => { if (inputRef.current) inputRef.current.focus(); }, 60);
    return () => clearTimeout(id);
  }, []);

  const pushLines = (newLines) => setLines(ls => [...ls, ...newLines]);

  const handleCommand = (raw) => {
    const cmd = raw.trim();
    pushLines([{ kind:'prompt', cwd, raw: cmd }]);
    if (!cmd) { pushLines([{kind:'spacer'}]); return; }

    setHistory(h => [...h, cmd]);

    const [op, ...args] = cmd.split(/\s+/);
    const arg = args.join(' ');

    switch (op) {
      case 'help': {
        pushLines([
          { kind:'ok', text:'commands —' },
          ...HELP_LINES.map(([c,d]) => ({ kind:'help', cmd:c, desc:d })),
          { kind:'spacer' },
        ]);
        break;
      }
      case 'ls': {
        const dir = arg ? resolvePath(cwd, arg) : cwd;
        const list = FS[dir];
        if (!list) { pushLines([{kind:'err', text:`ls: no such directory: ${dir}`},{kind:'spacer'}]); break; }
        pushLines([
          { kind:'ls', items:list },
          { kind:'spacer' },
        ]);
        break;
      }
      case 'cd': {
        if (!arg || arg === '~') { setCwd('~'); pushLines([{kind:'spacer'}]); break; }
        if (arg === '..') {
          if (cwd === '~') { pushLines([{kind:'spacer'}]); break; }
          const parent = cwd.replace(/\/[^/]+$/, '') || '~';
          setCwd(parent);
          pushLines([{kind:'spacer'}]);
          break;
        }
        const next = resolvePath(cwd, arg);
        if (FS[next]) { setCwd(next); pushLines([{kind:'spacer'}]); }
        else pushLines([{kind:'err', text:`cd: no such directory: ${arg}`},{kind:'spacer'}]);
        break;
      }
      case 'cat': {
        if (!arg) { pushLines([{kind:'err', text:'cat: needs a filename'},{kind:'spacer'}]); break; }
        const f = arg.split('/').pop();
        if (FILES[f]) pushLines([{kind:'ok', text:FILES[f]}, {kind:'spacer'}]);
        else pushLines([{kind:'err', text:`cat: no such file: ${arg}`},{kind:'spacer'}]);
        break;
      }
      case 'whoami': {
        pushLines([
          { kind:'ok',  text:'jeongwoo jang' },
          { kind:'dim', text:'ai automation engineer · hamburg, de · zürich, ch' },
          { kind:'dim', text:'curious doer · people-oriented · always asking why' },
          { kind:'spacer' },
        ]);
        break;
      }
      case 'now': {
        pushLines([
          { kind:'accent', text:'● now — joining [company], zürich · aug 2026' },
          { kind:'ok',  text:'shipping rag-eval-toolkit v0.3 next week' },
          { kind:'ok',  text:'writing about agentic eval (substack drop soon)' },
          { kind:'dim', text:'open to: collaborations, talks, gardening advice' },
          { kind:'spacer' },
        ]);
        break;
      }
      case 'stack': {
        pushLines([
          { kind:'ok',   text:'build:    rag · agentic · llmops · eval · hil' },
          { kind:'ok',   text:'lang:     python · typescript · sql' },
          { kind:'ok',   text:'platform: n8n · streamlit · fastapi · langchain' },
          { kind:'ok',   text:'data:     postgres · pgvector · duckdb' },
          { kind:'dim',  text:'+ infra, ci, observability — the unglamorous parts' },
          { kind:'spacer' },
        ]);
        break;
      }
      case 'hello': case 'hi': case 'hey': {
        pushLines([
          { kind:'accent', text:'hi.' },
          { kind:'dim',    text:'(also try: open contact)' },
          { kind:'spacer' },
        ]);
        break;
      }
      case 'open': {
        const valid = ['about','work','experience','writing','photos','hobbies','contact','terminal'];
        if (!arg || !valid.includes(arg)) { pushLines([{kind:'err', text:`open: try one of ${valid.join(', ')}`},{kind:'spacer'}]); break; }
        if (api && api.openApp) api.openApp(arg);
        pushLines([{kind:'ok', text:`launching ${arg}…`},{kind:'spacer'}]);
        break;
      }
      case 'donut': {
        if (api && api.triggerDonut) api.triggerDonut();
        pushLines([{kind:'accent', text:'● summoning torus —'}, {kind:'spacer'}]);
        break;
      }
      case 'echo': {
        pushLines([{kind:'ok', text:arg || ''},{kind:'spacer'}]);
        break;
      }
      case 'date': {
        pushLines([{kind:'ok', text:new Date().toString()},{kind:'spacer'}]);
        break;
      }
      case 'sudo': {
        pushLines([{kind:'err', text:'sudo: jang is not in the sudoers file. this incident will be… ignored.'},{kind:'spacer'}]);
        break;
      }
      case 'rm': case 'mv': {
        pushLines([{kind:'err', text:`${op}: refusing — this filesystem is read-only (and a portfolio).`},{kind:'spacer'}]);
        break;
      }
      case 'clear': {
        setLines([]);
        break;
      }
      case 'exit': case 'quit': {
        pushLines([{kind:'dim', text:'cannot exit. you are inside a portfolio website.'},{kind:'spacer'}]);
        break;
      }
      default: {
        pushLines([{kind:'err', text:`zsh: command not found: ${op} — try \`help\``}, {kind:'spacer'}]);
      }
    }
  };

  const onKeyDown = (e) => {
    if (e.key === 'Enter') {
      e.preventDefault();
      handleCommand(input);
      setInput('');
      setHistIdx(-1);
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      if (history.length === 0) return;
      const next = histIdx < 0 ? history.length - 1 : Math.max(0, histIdx - 1);
      setHistIdx(next);
      setInput(history[next]);
    } else if (e.key === 'ArrowDown') {
      e.preventDefault();
      if (histIdx < 0) return;
      const next = histIdx + 1;
      if (next >= history.length) { setHistIdx(-1); setInput(''); }
      else { setHistIdx(next); setInput(history[next]); }
    } else if (e.key === 'l' && e.ctrlKey) {
      e.preventDefault();
      setLines([]);
    }
  };

  return (
    <div className="terminal" ref={scrollRef} onMouseDown={(e) => { if (inputRef.current && e.target.tagName !== 'TEXTAREA') { e.preventDefault(); inputRef.current.focus(); } }}>
      {lines.map((l, i) => <Line key={i} line={l} />)}
      <div className="row">
        <span className="pr">jj@desktop {cwd} % </span>
        <textarea
          ref={inputRef}
          value={input}
          onChange={(e) => setInput(e.target.value.replace(/\n/g,''))}
          onKeyDown={onKeyDown}
          spellCheck={false}
          autoCapitalize="off"
          autoCorrect="off"
          rows={1}
          autoFocus
          aria-label="terminal input"
        />
      </div>
    </div>
  );
}

function Line({line}){
  switch (line.kind) {
    case 'prompt':
      return <div className="ln"><span className="pr">jj@desktop {line.cwd} % </span><span className="arg">{line.raw}</span></div>;
    case 'spacer':
      return <div className="ln">&nbsp;</div>;
    case 'help':
      return <div className="ln">  <span className="accent">{line.cmd.padEnd(13)}</span><span className="dim">{line.desc}</span></div>;
    case 'ls':
      // Render in columns
      return <div className="ln">{line.items.map((it, i) => <span key={i} style={{display:'inline-block', minWidth:'160px', color: it.endsWith('/') ? 'var(--accent-light)' : 'inherit'}}>{it}</span>)}</div>;
    case 'err':    return <div className={'ln err'}>{line.text}</div>;
    case 'accent': return <div className={'ln accent'}>{line.text}</div>;
    case 'dim':    return <div className={'ln dim'}>{line.text}</div>;
    case 'ok':
    default:       return <div className={'ln ok'}>{line.text}</div>;
  }
}

function resolvePath(cwd, arg){
  if (!arg) return cwd;
  if (arg === '~') return '~';
  if (arg === '..') {
    if (cwd === '~') return '~';
    return cwd.replace(/\/[^/]+$/, '') || '~';
  }
  if (arg.startsWith('~/')) return arg.replace(/\/$/, '');
  // relative
  const clean = arg.replace(/\/$/, '');
  return cwd === '~' ? `~/${clean}` : `${cwd}/${clean}`;
}

window.TerminalContent = TerminalContent;
