// Direction B — TERMINAL (real photo data)
// Center stage shows one real photo, surrounded by a chain strip.
// Fetches linked photos using the same API as the /live page.
// ?preview=true bypasses the odyssey rate limiter.

function Terminal({ speed = 1, mode = 'original', showCounter = true, showNav = true }) {
  const { chainRef, chainLen, extend } = usePhotoChain();
  const [idx, setIdx] = React.useState(0);
  const [tick, setTick] = React.useState(0);
  const [searchA, setSearchA] = React.useState('');
  const [searchB, setSearchB] = React.useState('');
  const [searching, setSearching] = React.useState(false);
  const [searchError, setSearchError] = React.useState(null);
  const [searchResult, setSearchResult] = React.useState(null);

  // Auto-advance through the chain
  React.useEffect(() => {
    if (chainLen === 0) return;
    const dwell = 3200 / speed;
    const t = setTimeout(() => {
      setIdx(i => {
        const next = i + 1;
        // Pre-fetch when nearing the end
        if (next + 3 >= chainLen) extend();
        return next < chainLen ? next : i;
      });
    }, dwell);
    return () => clearTimeout(t);
  }, [idx, speed, chainLen, extend]);

  // Bootstrap on mount
  React.useEffect(() => { extend(); }, [extend]);

  // Live clock
  React.useEffect(() => {
    const t = setInterval(() => setTick(x => x + 1), 1000);
    return () => clearInterval(t);
  }, []);

  const now = new Date();
  const timeStr = now.toUTCString().split(' ').slice(1, 5).join(' ');

  const stats = window.ARCHIVE_STATS || {};
  const peopleCount = Number(stats.people || (window.INITIAL_NAMES ? window.INITIAL_NAMES.length : 25390)).toLocaleString();
  const photosCount = Number(stats.photos || 48112).toLocaleString();

  // Nothing to show yet
  if (chainLen === 0) {
    return (
      <div style={{ position: 'absolute', inset: 0, background: 'var(--not-bg)', color: 'var(--not-fg)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <Header showNav={showNav} variant="terminal" />
        <span className="mono" style={{ fontSize: 10, color: 'var(--not-fg-fainter)', letterSpacing: '0.2em' }}>LOADING ARCHIVE…</span>
      </div>
    );
  }

  const safeIdx = Math.min(idx, chainLen - 1);
  const curEntry = chainRef.current[safeIdx];
  const cur = curEntry.photo;
  const curPeople = cur.People || [];

  // Build chain strip: 3 before, current, 3 after
  const WINDOW = 3;
  const chain = [];
  for (let k = -WINDOW; k <= WINDOW; k++) {
    const i = safeIdx + k;
    if (i < 0 || i >= chainLen) {
      chain.push({ entry: null, offset: k }); // placeholder slot
    } else {
      chain.push({ entry: chainRef.current[i], offset: k });
    }
  }

  // Determine shared people with prev/next for highlighting
  const prevEntry = safeIdx > 0 ? chainRef.current[safeIdx - 1] : null;
  const nextEntry = safeIdx < chainLen - 1 ? chainRef.current[safeIdx + 1] : null;
  const sharedIn  = prevEntry ? prevEntry.outboundName : null; // person connecting prev → cur
  const sharedOut = curEntry.outboundName;                      // person connecting cur → next

  // Search handler
  const handleSearch = async () => {
    if (!searchA.trim() || !searchB.trim() || searching) return;
    setSearching(true); setSearchError(null); setSearchResult(null);
    try {
      const resp = await fetch('/api/match', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'xsrf-token': getCsrfToken() },
        body: JSON.stringify({ first: searchA.trim(), last: searchB.trim() }),
      });
      const data = await resp.json();
      if (!resp.ok) {
        setSearchError(data.error || 'Query failed.');
      } else if (!data.photos || data.photos.length === 0) {
        setSearchError('No connection found between these two people.');
      } else {
        setSearchResult(data);
      }
    } catch (e) {
      setSearchError('Connection error. Please try again.');
    } finally {
      setSearching(false);
    }
  };

  const fillChip = (a, b) => { setSearchA(a); setSearchB(b); setSearchResult(null); setSearchError(null); };

  return (
    <div className="terminal" style={{
      position: 'absolute', inset: 0,
      background: 'var(--not-bg)', color: 'var(--not-fg)', overflow: 'hidden',
    }}>
      <Header showNav={showNav} variant="terminal" />

      {/* Left rail — metadata */}
      <aside className="term-rail term-rail--left">
        <div className="term-rail-block">
          <div className="term-rail-label mono">NOW DISPLAYING</div>
          <div className="term-rail-val serif-num">{String(safeIdx + 1).padStart(4, '0')}</div>
          <div className="term-rail-sub mono">of {String(chainLen).padStart(4, '0')} in current chain</div>
        </div>
        <div className="term-rail-block">
          <div className="term-rail-label mono">YEAR</div>
          <div className="term-rail-val serif-num">{cur.Year || cur.year || '—'}</div>
        </div>
        {(cur.Photographer || cur.photographer) && (
          <div className="term-rail-block">
            <div className="term-rail-label mono">PHOTOGRAPHER</div>
            <div className="term-rail-val-sm">{cur.Photographer || cur.photographer}</div>
          </div>
        )}
        {(cur.Location || cur.location) && (
          <div className="term-rail-block">
            <div className="term-rail-label mono">LOCATION</div>
            <div className="term-rail-val-sm">{cur.Location || cur.location}</div>
          </div>
        )}
        <div className="term-rail-block term-rail-block--people">
          <div className="term-rail-label mono">PEOPLE IN FRAME</div>
          {curPeople.map((p, i) => {
            const nm = p.Name || p.name;
            const isOut = nm === sharedOut;
            const isIn  = nm === sharedIn;
            return (
              <div key={i} className={'term-person' + (isOut ? ' term-person--linked-out' : isIn ? ' term-person--linked-in' : '')}>
                <span className="term-person-mark">{isIn ? '←' : isOut ? '→' : '·'}</span>
                <span className="term-person-name">{nm}</span>
              </div>
            );
          })}
        </div>
      </aside>

      {/* Center — chain strip */}
      <div className="term-stage">
        <div className="term-strip">
          {chain.map(({ entry, offset }) => {
            if (!entry) {
              // Placeholder slot (before beginning or past end of chain)
              const dist = Math.abs(offset);
              return (
                <div key={'empty-' + offset}
                  className={'term-card' + (offset < 0 ? ' term-card--past' : ' term-card--future')}
                  style={{ '--dist': dist }}>
                  <div className="term-card-img" style={{ background: '#0a0908', opacity: 0.3 }} />
                </div>
              );
            }

            const isCur = offset === 0;
            const dist = Math.abs(offset);
            const photo = entry.photo;

            // Connection line to the right (outboundName links this to the next entry)
            const sharedHere = offset < WINDOW ? entry.outboundName : null;

            return (
              <div
                key={photo.PhotoID + '@' + offset}
                className={'term-card' + (isCur ? ' term-card--cur' : '') +
                  (offset < 0 ? ' term-card--past' : offset > 0 ? ' term-card--future' : '')}
                style={{ '--dist': dist }}
              >
                <div className="term-card-img">
                  <TerminalPhotoCard
                    photo={photo}
                    mode={mode}
                    isCur={isCur}
                    highlightPerson={isCur ? sharedOut : null}
                  />
                </div>
                <div className="term-card-meta mono">
                  <span>{photo.Year || photo.year || ''}</span>
                  <span className="term-card-id">{(photo.PhotoID || '').toUpperCase().slice(0, 8)}</span>
                </div>
                {sharedHere && offset < WINDOW && (
                  <div className="term-link">
                    <svg width="100%" height="24" viewBox="0 0 100 24" preserveAspectRatio="none">
                      <path d="M 0 12 L 100 12" stroke="oklch(0.7 0.09 78 / 0.55)" strokeWidth="0.6" strokeDasharray="2 2" />
                      <circle cx="0"   cy="12" r="1.6" fill="oklch(0.82 0.11 78)" />
                      <circle cx="100" cy="12" r="1.6" fill="oklch(0.82 0.11 78)" />
                    </svg>
                    <div className="term-link-label mono">{sharedHere}</div>
                  </div>
                )}
              </div>
            );
          })}
        </div>

        {/* Center caption */}
        <div className="term-center-caption">
          <div className="term-center-names">
            {curPeople.map((p, i) => {
              const nm = p.Name || p.name;
              const linked = nm === sharedOut || nm === sharedIn;
              return (
                <React.Fragment key={i}>
                  <span className={'caption-name' + (linked ? ' linked' : '')}>{nm}</span>
                  {i < curPeople.length - 1 && <span className="caption-sep">·</span>}
                </React.Fragment>
              );
            })}
          </div>
        </div>
      </div>

      {/* Right rail — live readouts */}
      <aside className="term-rail term-rail--right">
        <div className="term-rail-block">
          <div className="term-rail-label mono">SYSTEM TIME</div>
          <div className="term-rail-val-sm mono">{timeStr} UTC</div>
        </div>
        {showCounter && (
          <div className="term-rail-block">
            <div className="term-rail-label mono">ARCHIVE</div>
            <div className="term-ticker">
              <div className="term-ticker-row"><span>people</span><span className="mono">{peopleCount}</span></div>
              <div className="term-ticker-row"><span>photographs</span><span className="mono">{photosCount}</span></div>
              <div className="term-ticker-row"><span>submissions today</span><span className="mono">+{12 + (tick % 7)}</span></div>
            </div>
          </div>
        )}
        {prevEntry && (
          <div className="term-rail-block">
            <div className="term-rail-label mono">CURRENT LINK</div>
            <div className="term-link-box">
              <div className="term-link-row">
                <span className="mono">FROM</span>
                <span>{(prevEntry.photo.People || [])[0]?.Name || '—'}</span>
              </div>
              <div className="term-link-arrow mono">↓ via <span className="link-shared">{sharedIn || '—'}</span></div>
              <div className="term-link-row">
                <span className="mono">TO</span>
                <span>{curPeople[curPeople.length - 1]?.Name || '—'}</span>
              </div>
            </div>
          </div>
        )}
        <div className="term-rail-block">
          <div className="term-rail-label mono">STATUS</div>
          <div className="term-status"><span className="term-status-dot" /> <span className="mono">LIVE · AUTO-ADVANCE</span></div>
        </div>
      </aside>

      {/* Bottom search strip */}
      <div className="term-search">
        <div className="term-search-head">
          <div className="tag-serif">All of our lives overlap in the Network of Time.</div>
        </div>

        {searchResult ? (
          <div style={{ maxWidth: 1100, margin: '0 auto', display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
            <span className="mono" style={{ fontSize: 9, color: 'var(--not-accent)', letterSpacing: '0.2em' }}>
              CONNECTION · {searchResult.photos.length} STEPS
            </span>
            {searchResult.photos.map((p, i) => (
              <React.Fragment key={i}>
                <span style={{ fontFamily: 'var(--serif)', fontSize: 13 }}>
                  {(p.people || p.People || []).map(pp => pp.Name || pp.name || pp).join(', ') || '—'}
                </span>
                {i < searchResult.photos.length - 1 && (
                  <span className="mono" style={{ color: 'var(--not-accent)', fontSize: 11 }}>→</span>
                )}
              </React.Fragment>
            ))}
            <button className="term-chip" onClick={() => { setSearchResult(null); setSearchA(''); setSearchB(''); }}>Clear</button>
            <a href="/odyssey" className="term-chip" style={{ textDecoration: 'none' }}>Odyssey →</a>
          </div>
        ) : (
          <div className="term-search-row">
            <div className="term-search-field">
              <span className="term-search-label mono">PERSON 01</span>
              <input className="term-search-input" placeholder="type any person's name"
                value={searchA}
                onChange={e => { setSearchA(e.target.value); setSearchError(null); }}
                onKeyDown={e => e.key === 'Enter' && handleSearch()} />
            </div>
            <div className="term-search-bridge mono">↔</div>
            <div className="term-search-field">
              <span className="term-search-label mono">PERSON 02</span>
              <input className="term-search-input" placeholder="and any other person"
                value={searchB}
                onChange={e => { setSearchB(e.target.value); setSearchError(null); }}
                onKeyDown={e => e.key === 'Enter' && handleSearch()} />
            </div>
            <button className="term-search-btn" onClick={handleSearch} disabled={searching}>
              <span>{searching ? 'Searching…' : 'Discover connection'}</span>
              <svg width="16" height="10" viewBox="0 0 18 12" fill="none">
                <path d="M1 6 H17 M12 1 L17 6 L12 11" stroke="currentColor" strokeWidth="1.2" />
              </svg>
            </button>
          </div>
        )}

        <div className="term-search-foot mono">
          {searchError
            ? <span style={{ color: 'oklch(0.65 0.15 25)' }}>{searchError}</span>
            : <>
                <span>try:</span>
                <button className="term-chip" onClick={() => fillChip('Dwight D. Eisenhower', 'Madonna')}>Dwight D. Eisenhower ↔ Madonna</button>
                <button className="term-chip" onClick={() => fillChip('Marie Curie', 'Keith Haring')}>Marie Curie ↔ Keith Haring</button>
                <button className="term-chip" onClick={() => fillChip('Nikola Tesla', 'Lou Reed')}>Nikola Tesla ↔ Lou Reed</button>
              </>
          }
          <span className="term-foot-right">or <a href="/odyssey">explore via Odyssey →</a></span>
        </div>
      </div>
    </div>
  );
}

// ─── Terminal photo card ───────────────────────────────────────
// Renders a real photo within the chain strip card.
// The card size is controlled by CSS (.term-card-img width/opacity rules).
function TerminalPhotoCard({ photo, mode, isCur, highlightPerson }) {
  const [loaded, setLoaded] = React.useState(false);
  const [annotations, setAnnotations] = React.useState([]);

  const handleLoad = React.useCallback((e) => {
    const img = e.target;
    const natW = img.naturalWidth  || 400;
    const natH = img.naturalHeight || 500;
    const cardW = isCur ? 320 : 200;
    // Actual rendered height when image fills the CSS-controlled width at natural AR
    const actualH = Math.round(cardW * natH / natW);
    const anns = parseAnnotations(photo);
    const parsed = (photo.People || []).map(person => {
      const ann = anns.find(a =>
        (a.personName === person.Name || a.name === person.Name) ||
        (a.personId === person.PersonID || a.personID === person.PersonID || a.PersonID === person.PersonID)
      );
      if (!ann) return null;
      const box = extractBox(ann, natW, natH, cardW, actualH);
      if (!box) return null;
      return { name: person.Name, box };
    }).filter(Boolean);
    setAnnotations(parsed);
    setLoaded(true);
  }, [photo, isCur]);

  const cardW = isCur ? 320 : 200;
  const cardH = cardW * 1.25;

  const highlightAnn = highlightPerson && annotations.find(a => a.name === highlightPerson);

  return (
    <div style={{
      position: 'relative', width: '100%', overflow: 'hidden',
      // Show striped shimmer as the background while image loads; give it a minimum
      // height so the card isn't collapsed before the image arrives.
      minHeight: loaded ? 0 : (isCur ? 240 : 150),
      background: loaded
        ? '#0a0908'
        : 'repeating-linear-gradient(-15deg, rgba(30,25,20,0.85) 0 3px, rgba(10,9,8,0.9) 3px 14px)',
    }}>
      <img
        src={photo.PhotoMeta}
        alt={photo.PhotoDescription || ''}
        onLoad={handleLoad}
        style={{
          display: 'block', width: '100%', height: 'auto',
          opacity: loaded ? 1 : 0,
          transition: 'opacity 0.4s ease',
          filter: mode === 'bw' ? 'grayscale(100%)' : 'none',
        }}
      />
      {/* Vignette */}
      <div style={{
        position: 'absolute', inset: 0, pointerEvents: 'none',
        background: 'radial-gradient(ellipse at center, transparent 40%, rgba(0,0,0,0.5) 100%)',
      }} />
      {/* Highlight ring on shared person (current card only) */}
      {highlightAnn && loaded && (
        <div style={{
          position: 'absolute',
          left: highlightAnn.box.left,
          top: highlightAnn.box.top,
          width: highlightAnn.box.width,
          height: highlightAnn.box.height,
          border: '1.5px solid oklch(0.84 0.11 78)',
          boxShadow: '0 0 0 1px rgba(0,0,0,0.6), 0 0 18px rgba(230,180,90,0.35)',
          pointerEvents: 'none',
          animation: 'notPulse 2.4s ease-in-out infinite',
        }} />
      )}
    </div>
  );
}

Object.assign(window, { Terminal });
