// Scoped in an IIFE: this file shares global scope with the other page
// entries, and the router now loads all of them into one document. Names
// like App, Hero, Footer, Cover and C are declared by several of them, so
// leaking them at top level lets the last-loaded page silently clobber the
// others' components. Only window.Pages.<ns> is exported.
(function () {
const { useState, useEffect, useRef, useCallback } = React;
const {
  EyeGlyph, MouthGlyph, EarGlyph, BrainGlyph, HandGlyph,
} = window.Marks;

function App() {
  const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
    "layout": "A"
  }/*EDITMODE-END*/;

  const [tweaks, setTweaks] = useState(TWEAK_DEFAULTS);
  const [tweaksOpen, setTweaksOpen] = useState(false);

  useEffect(() => {
    const handler = (e) => {
      if (e.data?.type === '__activate_edit_mode') setTweaksOpen(true);
      if (e.data?.type === '__deactivate_edit_mode') setTweaksOpen(false);
    };
    window.addEventListener('message', handler);
    window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', handler);
  }, []);

  const updateTweak = (k, v) => {
    setTweaks(prev => {
      const next = { ...prev, [k]: v };
      window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [k]: v } }, '*');
      return next;
    });
  };

  const layout = window.LAYOUTS[tweaks.layout] || window.LAYOUTS.A;

  // chat
  const [input, setInput] = useState('');
  const [messages, setMessages] = useState([]);
  const [thinking, setThinking] = useState(false);
  const [speaking, setSpeaking] = useState(false);
  const [chatOpen, setChatOpen] = useState(false);
  const [listening, setListening] = useState(false);
  const logRef = useRef(null);

  useEffect(() => {
    if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight;
  }, [messages, thinking]);

  // eye tracking
  const [pupil, setPupil] = useState({ x: 0, y: 0 });
  const [blink, setBlink] = useState(false);
  useEffect(() => {
    const onMove = (e) => {
      const el = document.querySelector('[data-blob-id="eye"]');
      if (!el) return;
      const r = el.getBoundingClientRect();
      const cx = r.left + r.width / 2;
      const cy = r.top + r.height / 2;
      setPupil({
        x: Math.max(-1, Math.min(1, (e.clientX - cx) / 400)),
        y: Math.max(-1, Math.min(1, (e.clientY - cy) / 300)),
      });
    };
    window.addEventListener('mousemove', onMove);
    return () => window.removeEventListener('mousemove', onMove);
  }, []);
  useEffect(() => {
    const t = setInterval(() => {
      setBlink(true);
      setTimeout(() => setBlink(false), 140);
    }, 4500 + Math.random() * 2500);
    return () => clearInterval(t);
  }, []);

  // brain pulse
  const [brainPulse, setBrainPulse] = useState(0);
  useEffect(() => {
    let raf;
    const loop = (t) => {
      setBrainPulse((Math.sin(t / 900) + 1) / 2 * 0.3 + (thinking ? 0.7 : 0));
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [thinking]);

  // mouth
  const [mouthOpen, setMouthOpen] = useState(0);
  useEffect(() => {
    if (!speaking) { setMouthOpen(0); return; }
    let raf;
    const loop = (t) => {
      setMouthOpen(0.2 + Math.abs(Math.sin(t / 80)) * 0.8);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [speaking]);

  const send = useCallback(async (raw) => {
    const text = (raw ?? input).trim();
    if (!text || thinking) return;
    setInput('');
    setChatOpen(true);
    const uid = Date.now();
    setMessages(m => [...m, { id: uid, role: 'user', text }]);
    setThinking(true);
    await new Promise(r => setTimeout(r, 650));
    const reply = await window.AI.askAI(text);
    setThinking(false);
    setSpeaking(true);
    setMessages(m => [...m, { id: uid + 1, role: 'ai', text: '' }]);
    let i = 0;
    const step = () => {
      i += 1;
      setMessages(m => {
        const copy = [...m];
        copy[copy.length - 1] = { ...copy[copy.length - 1], text: reply.slice(0, i) };
        return copy;
      });
      if (i < reply.length) setTimeout(step, 18 + Math.random() * 20);
      else setSpeaking(false);
    };
    setTimeout(step, 120);
  }, [input, thinking]);

  const toggleVoice = () => {
    if (listening) { setListening(false); return; }
    setListening(true);
    setTimeout(() => {
      setListening(false);
      send("Tell me about your projects.");
    }, 2400);
  };

  const renderOrgan = (kind) => {
    if (kind === 'eye')   return <window.BauhausEye pupilX={pupil.x} pupilY={pupil.y} blink={blink} s={220} />;
    if (kind === 'mouth') return <MouthGlyph open={mouthOpen} s={180} />;
    if (kind === 'ear')   return (
      <div onClick={toggleVoice} style={{ cursor: 'pointer', position: 'relative', width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <window.BauhausEar listening={listening} s={210} />
        {listening && <ListenRing />}
      </div>
    );
    if (kind === 'brain') return <BrainGlyph pulse={brainPulse} s={180} />;
    if (kind === 'hand')  return <window.BauhausHand s={280} />;
    return null;
  };

  return (
    <div style={{
      position: 'fixed', inset: 0,
      background: 'var(--paper)',
      color: 'var(--ink)',
      fontFamily: "'Space Grotesk', system-ui, sans-serif",
      overflow: 'hidden',
    }}>
      {/* Poster header */}
      <window.Chrome.Nav active="Work" />

      {/* Poster canvas — the blob grid */}
      <div style={{
        position: 'absolute',
        left: '4%', right: '4%',
        // Clears the nav, whose height is --bar-h (96/72/60 across tiers). The
        // old literal 76px was tuned for the deleted absolute header.
        top: 'var(--bar-h)',
        bottom: '210px',
      }}>
        {layout.map(b => {
          const focused =
            (thinking && b.id === 'brain') ||
            (speaking && b.id === 'mouth') ||
            (listening && b.id === 'ear');
          return (
            <window.Blob key={b.id} blob={b} focused={focused}
              organContent={renderOrgan(b.kind)} />
          );
        })}
      </div>

      {/* Footer meta (like poster) */}
      <Footer />

      {/* Chat overlay */}
      {chatOpen && (
        <ChatPanel
          messages={messages} thinking={thinking}
          onClose={() => setChatOpen(false)} logRef={logRef}
        />
      )}

      {/* Input bar */}
      <InputBar
        value={input} onChange={setInput}
        onSend={send}
        onTemplate={(q) => send(q)}
        thinking={thinking} listening={listening}
        onMic={toggleVoice}
      />

      {tweaksOpen && (
        <TweaksPanel tweaks={tweaks} onUpdate={updateTweak}
          onClose={() => setTweaksOpen(false)} />
      )}
    </div>
  );
}

// ---- chrome ----

function Footer() {
  return (
    <div style={{
      position: 'absolute', left: '4%', right: '4%', bottom: 160,
      display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end',
      fontFamily: "'Space Grotesk', sans-serif",
      fontSize: 9, letterSpacing: '0.1em', textTransform: 'uppercase',
      zIndex: 3,
      pointerEvents: 'none',
      borderTop: '1px solid var(--ink)',
      paddingTop: 10,
    }}>
      <div>
        <div style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: 13, fontStyle: 'italic', textTransform: 'none', letterSpacing: 0 }}>sensory</div>
        <div style={{ fontSize: 18, fontWeight: 700, letterSpacing: '-0.01em', textTransform: 'none', lineHeight: 1 }}>Portfolio</div>
      </div>
      <div style={{ textAlign: 'center' }}>
        <div style={{ fontWeight: 700 }}>AI ENGINEER</div>
        <div style={{ opacity: 0.65 }}>SINCE 2019</div>
      </div>
      <div style={{ textAlign: 'right' }}>
        <div style={{ fontWeight: 700 }}>FLAT, MINIMAL</div>
        <div style={{ opacity: 0.65 }}>&amp; GEOMETRIC</div>
      </div>
    </div>
  );
}

function ListenRing() {
  return (
    <div style={{
      position: 'absolute', inset: -14,
      border: '2px solid var(--ink)',
      borderRadius: '50%',
      animation: 'pulse-ring 1.2s ease-out infinite',
      pointerEvents: 'none',
    }} />
  );
}

// ---- chat ----

function ChatPanel({ messages, thinking, onClose, logRef }) {
  return (
    <div style={{
      position: 'absolute',
      left: '50%', transform: 'translateX(-50%)',
      bottom: 170,
      width: 'min(680px, 92vw)',
      maxHeight: '44vh',
      zIndex: 15,
      display: 'flex', flexDirection: 'column',
      background: 'rgba(237, 230, 220, 0.92)',
      backdropFilter: 'blur(20px)',
      WebkitBackdropFilter: 'blur(20px)',
      border: '1.5px solid var(--ink)',
      borderRadius: 24, padding: '18px 22px',
      animation: 'fade-up-centered 400ms cubic-bezier(.2,.8,.2,1)',
    }}>
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        marginBottom: 10,
        fontFamily: "'JetBrains Mono', monospace",
        fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase',
        opacity: 0.6,
      }}>
        <span>transcript</span>
        <button onClick={onClose} style={{
          background: 'none', border: 'none', color: 'var(--ink)',
          cursor: 'pointer', opacity: 0.6, fontSize: 11,
          fontFamily: 'inherit',
        }}>close ✕</button>
      </div>
      <div ref={logRef} style={{ overflowY: 'auto', flex: 1, paddingRight: 8 }}>
        {messages.map(m => (
          <div key={m.id} style={{
            margin: '10px 0',
            fontSize: 15, lineHeight: 1.55,
            color: 'var(--ink)',
          }}>
            <span style={{
              fontFamily: "'JetBrains Mono', monospace",
              fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase',
              opacity: 0.6, marginRight: 10,
            }}>
              {m.role === 'user' ? 'you' : 'ai'}
            </span>
            {m.text}
            {m.role === 'ai' && m.text.length > 0 && messages[messages.length - 1].id === m.id && (
              <span style={{
                display: 'inline-block', width: 8, height: 16,
                background: 'var(--ink)', marginLeft: 3, verticalAlign: -3,
                animation: 'blink 1s steps(2) infinite',
              }} />
            )}
          </div>
        ))}
        {thinking && (
          <div style={{
            fontFamily: "'JetBrains Mono', monospace",
            fontSize: 11, letterSpacing: '0.14em',
            opacity: 0.7, margin: '10px 0',
          }}>
            thinking<span className="dots">...</span>
          </div>
        )}
      </div>
    </div>
  );
}

function InputBar({ value, onChange, onSend, onTemplate, thinking, listening, onMic }) {
  const templates = window.AI.TEMPLATE_QUESTIONS;
  return (
    <div style={{
      position: 'absolute', bottom: 0, left: 0, right: 0,
      padding: '12px 4% 18px',
      zIndex: 18,
    }}>
      <div style={{
        display: 'flex', gap: 8, marginBottom: 10, flexWrap: 'wrap',
        justifyContent: 'center',
      }}>
        {templates.map(t => (
          <button key={t.tag} onClick={() => onTemplate(t.q)}
            disabled={thinking}
            style={{
              padding: '7px 14px',
              background: 'transparent',
              border: '1.2px solid var(--ink)',
              borderRadius: 999,
              color: 'var(--ink)',
              fontFamily: "'JetBrains Mono', monospace",
              fontSize: 11, letterSpacing: '0.02em',
              cursor: thinking ? 'default' : 'pointer',
              opacity: thinking ? 0.4 : 0.9,
              transition: 'all 180ms',
            }}
            onMouseEnter={(e) => { if (!thinking) { e.currentTarget.style.background = 'var(--ink)'; e.currentTarget.style.color = 'var(--paper)'; } }}
            onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--ink)'; }}
          >
            {t.q}
          </button>
        ))}
      </div>

      <form onSubmit={(e) => { e.preventDefault(); onSend(); }}
        style={{
          display: 'flex', alignItems: 'center', gap: 10,
          maxWidth: 720, margin: '0 auto',
          background: 'var(--paper)',
          border: `1.5px solid var(--ink)`,
          borderRadius: 100,
          padding: '8px 8px 8px 22px',
          boxShadow: listening ? '0 0 0 4px rgba(26,26,26,0.12)' : 'none',
          transition: 'box-shadow 200ms',
        }}>
        <span style={{
          fontFamily: "'JetBrains Mono', monospace",
          fontSize: 13, fontWeight: 600,
        }}>{'>'}</span>
        <input
          value={value}
          onChange={(e) => onChange(e.target.value)}
          placeholder={listening ? 'listening…' : 'ask the page anything'}
          disabled={thinking || listening}
          style={{
            flex: 1, background: 'transparent', border: 'none', outline: 'none',
            color: 'var(--ink)', fontSize: 15,
            fontFamily: "'Space Grotesk', sans-serif",
          }}
        />
        <button type="button" onClick={onMic} title="voice"
          style={{
            width: 36, height: 36, borderRadius: '50%',
            background: listening ? 'var(--ink)' : 'transparent',
            border: '1.2px solid var(--ink)', cursor: 'pointer',
            color: listening ? 'var(--paper)' : 'var(--ink)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            transition: 'all 200ms',
          }}>
          <svg width="12" height="16" viewBox="0 0 14 18" fill="none">
            <rect x="4" y="1" width="6" height="10" rx="3" fill="currentColor" />
            <path d="M1 8 Q 1 13 7 13 Q 13 13 13 8" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" />
            <line x1="7" y1="13" x2="7" y2="17" stroke="currentColor" strokeWidth="1.5" />
          </svg>
        </button>
        <button type="submit" disabled={thinking || !value.trim()}
          style={{
            width: 36, height: 36, borderRadius: '50%',
            background: value.trim() && !thinking ? 'var(--ink)' : 'transparent',
            border: '1.2px solid var(--ink)',
            cursor: value.trim() && !thinking ? 'pointer' : 'default',
            color: value.trim() && !thinking ? 'var(--paper)' : 'var(--ink)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            transition: 'all 200ms',
          }}>
          <svg width="13" height="13" viewBox="0 0 14 14" fill="none">
            <path d="M2 7 L 12 7 M 8 3 L 12 7 L 8 11" stroke="currentColor" strokeWidth="1.8" fill="none" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
        </button>
      </form>

      <div style={{
        textAlign: 'center', marginTop: 8,
        fontFamily: "'JetBrains Mono', monospace",
        fontSize: 9, letterSpacing: '0.18em', textTransform: 'uppercase',
        opacity: 0.55,
      }}>
        the eye follows · the ear listens · the mouth speaks
      </div>
    </div>
  );
}

function TweaksPanel({ tweaks, onUpdate, onClose }) {
  return (
    <div style={{
      position: 'fixed', right: 20, top: 100, zIndex: 40,
      background: 'var(--paper)',
      border: '1.5px solid var(--ink)',
      borderRadius: 16, padding: 18, width: 240,
      color: 'var(--ink)',
      fontFamily: "'JetBrains Mono', monospace",
      boxShadow: '0 20px 60px -20px rgba(0,0,0,0.25)',
    }}>
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        marginBottom: 14,
        fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase',
        opacity: 0.7,
      }}>
        <span>Tweaks</span>
        <button onClick={onClose} style={{
          background: 'none', border: 'none', color: 'inherit',
          cursor: 'pointer', opacity: 0.6, fontSize: 12,
        }}>✕</button>
      </div>
      <div style={{ fontSize: 10, opacity: 0.55, marginBottom: 8, letterSpacing: '0.14em' }}>
        COMPOSITION
      </div>
      <div style={{ display: 'flex', gap: 8 }}>
        {[
          { key: 'A', label: 'Safe' },
          { key: 'B', label: 'Experimental' },
        ].map(opt => (
          <button key={opt.key}
            onClick={() => onUpdate('layout', opt.key)}
            style={{
              flex: 1, padding: '10px 8px', borderRadius: 10,
              background: tweaks.layout === opt.key ? 'var(--ink)' : 'transparent',
              color: tweaks.layout === opt.key ? 'var(--paper)' : 'var(--ink)',
              border: '1.2px solid var(--ink)', cursor: 'pointer',
              fontFamily: 'inherit', fontSize: 11, letterSpacing: '0.08em',
            }}>
            {opt.label}
          </button>
        ))}
      </div>
    </div>
  );
}

// Registered, not mounted: router.js owns mounting so Barba can swap
// containers and re-mount without a full page load.
window.Pages = window.Pages || {};
window.Pages.work = App;
})();
