const { useState, useEffect, useRef, useLayoutEffect } = React;

// Shared kill-ring for Ctrl+K / Ctrl+U / Ctrl+W / Ctrl+Y across every editor instance.
let editorKillRing = '';

// A monospace, cloud-synced plain-text editor with readline/emacs keybindings.
// Controlled locally (seeded from `value`); remount via `key` to switch documents.
const TextEditor = ({ value, onSave, onTyping, onCopy, onFocusChange, placeholder, autoFocus, minHeight = '40vh' }) => {
  const [text, setText] = useState(value || '');
  const [status, setStatus] = useState('saved'); // 'saved' | 'saving'
  const taRef = useRef(null);
  const pendingSelRef = useRef(null);
  const saveTimerRef = useRef(null);

  // Restore the caret after a controlled re-render driven by a readline op.
  useLayoutEffect(() => {
    if (pendingSelRef.current != null && taRef.current) {
      const [s, e] = pendingSelRef.current;
      taRef.current.selectionStart = s;
      taRef.current.selectionEnd = e;
      pendingSelRef.current = null;
    }
  }, [text]);

  useEffect(() => () => { if (saveTimerRef.current) clearTimeout(saveTimerRef.current); }, []);

  const scheduleSave = (next) => {
    setStatus('saving');
    if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
    saveTimerRef.current = setTimeout(() => { onSave(next); setStatus('saved'); }, 600);
  };
  const flush = () => {
    if (saveTimerRef.current) { clearTimeout(saveTimerRef.current); saveTimerRef.current = null; }
    onSave(taRef.current ? taRef.current.value : text);
    setStatus('saved');
  };
  const commit = (next, selStart, selEnd) => {
    const sEnd = selEnd == null ? selStart : selEnd;
    if (next === text) {
      if (taRef.current) { taRef.current.selectionStart = selStart; taRef.current.selectionEnd = sEnd; }
    } else {
      pendingSelRef.current = [selStart, sEnd];
      setText(next);
      scheduleSave(next);
    }
  };

  const handleChange = (e) => {
    const next = e.target.value;
    const delta = next.length - text.length;
    if (delta > 0 && onTyping) onTyping(delta);
    setText(next);
    scheduleSave(next);
  };

  const wordStart = (str, pos) => { let i = pos; while (i > 0 && /\s/.test(str[i-1])) i--; while (i > 0 && !/\s/.test(str[i-1])) i--; return i; };
  const wordEnd = (str, pos) => { let i = pos; while (i < str.length && /\s/.test(str[i])) i++; while (i < str.length && !/\s/.test(str[i])) i++; return i; };
  const lineStart = (str, pos) => str.lastIndexOf('\n', pos - 1) + 1;
  const lineEnd = (str, pos) => { const i = str.indexOf('\n', pos); return i === -1 ? str.length : i; };

  const handleKeyDown = (e) => {
    const ta = taRef.current; if (!ta) return;
    const val = ta.value, s = ta.selectionStart, en = ta.selectionEnd;
    const ctrl = e.ctrlKey && !e.metaKey, alt = e.altKey;

    if (ctrl && !alt) {
      switch (e.key) {
        case 'a': e.preventDefault(); commit(val, lineStart(val, s)); return;
        case 'e': e.preventDefault(); commit(val, lineEnd(val, s)); return;
        case 'k': { e.preventDefault(); const le = lineEnd(val, s); const cut = s === le ? val.slice(s, s+1) : val.slice(s, le); if (cut) editorKillRing = cut; const end = s === le ? s+1 : le; commit(val.slice(0, s) + val.slice(end), s); return; }
        case 'u': { e.preventDefault(); const ls = lineStart(val, s); if (val.slice(ls, s)) editorKillRing = val.slice(ls, s); commit(val.slice(0, ls) + val.slice(s), ls); return; }
        case 'w': { e.preventDefault(); const ws = wordStart(val, s); if (val.slice(ws, s)) editorKillRing = val.slice(ws, s); commit(val.slice(0, ws) + val.slice(s), ws); return; }
        case 'd': { e.preventDefault(); if (s !== en) commit(val.slice(0, s) + val.slice(en), s); else if (s < val.length) commit(val.slice(0, s) + val.slice(s+1), s); return; }
        case 'h': { e.preventDefault(); if (s !== en) commit(val.slice(0, s) + val.slice(en), s); else if (s > 0) commit(val.slice(0, s-1) + val.slice(s), s-1); return; }
        case 'y': { e.preventDefault(); const ins = editorKillRing || ''; commit(val.slice(0, s) + ins + val.slice(en), s + ins.length); return; }
        case 's': e.preventDefault(); flush(); return;
        default: return;
      }
    }
    if (alt && !ctrl) {
      if (e.key === 'b' || e.key === 'B') { e.preventDefault(); commit(val, wordStart(val, s)); return; }
      if (e.key === 'f' || e.key === 'F') { e.preventDefault(); commit(val, wordEnd(val, s)); return; }
    }
  };

  return (
    <div className="flex flex-col h-full min-h-0">
      <textarea
        ref={taRef}
        value={text}
        onChange={handleChange}
        onKeyDown={handleKeyDown}
        onCopy={() => onCopy && onCopy()}
        onFocus={() => onFocusChange && onFocusChange(true)}
        onBlur={() => { flush(); onFocusChange && onFocusChange(false); }}
        placeholder={placeholder}
        autoFocus={autoFocus}
        spellCheck={false}
        className="w-full flex-1 bg-pink-50/30 rounded-2xl p-4 outline-none font-mono text-sm leading-relaxed text-slate-700 resize-none focus:bg-pink-50/60 transition-all duration-200 border border-transparent focus:border-pink-100"
        style={{ minHeight }}
      />
      <div className="flex justify-between items-center mt-2 px-1 text-[10px] uppercase tracking-widest font-bold text-pink-300">
        <span>terminal-style · Ctrl+/ for keys</span>
        <span>{status === 'saving' ? 'Saving…' : 'Saved ✓'}</span>
      </div>
    </div>
  );
};

window.TextEditor = TextEditor;
