// screens2.jsx — Claim, Detail, Passport, Complete, Watch. Uses window.Icon, window.Patch.

const Icon2 = window.Icon;
const Patch2 = window.Patch;

// ============================================================ CLAIM
// claimStyle: 'hold' (hold select to fill ring) | 'pinch' (single select/tap)
function ClaimScreen({ site, shape, claimStyle, onClaimed }) {
  const [prog, setProg] = React.useState(0);   // 0..1
  const [done, setDone] = React.useState(false);
  const holding = React.useRef(false);
  const raf = React.useRef(0);
  const last = React.useRef(0);
  const HOLD_MS = 1050;

  const finish = React.useCallback(() => {
    if (done) return;
    setDone(true);
    setProg(1);
    // Linger on the "Patch claimed / Secret location unlocked" beat so it's
    // readable — longer when a secret unlocks. (Was 720ms, too fast to read.)
    setTimeout(() => onClaimed(), site.secret ? 2600 : 1200);
  }, [done, onClaimed, site.secret]);

  // hold loop
  React.useEffect(() => {
    if (claimStyle !== "hold") return;
    function tick(t) {
      if (!last.current) last.current = t;
      const dt = t - last.current; last.current = t;
      setProg((p) => {
        let np = holding.current ? p + dt / HOLD_MS : Math.max(0, p - dt / (HOLD_MS * 0.6));
        if (np >= 1) { np = 1; }
        return np;
      });
      raf.current = requestAnimationFrame(tick);
    }
    raf.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf.current);
  }, [claimStyle]);

  React.useEffect(() => { if (prog >= 1 && !done) finish(); }, [prog, done, finish]);

  // input wiring
  React.useEffect(() => {
    const down = (e) => {
      if (e.repeat) return;
      if (e.key === "Enter" || e.key === " " || e.key === "ArrowRight") {
        e.preventDefault();
        if (claimStyle === "pinch") finish();
        else holding.current = true;
      }
    };
    const up = (e) => {
      if (e.key === "Enter" || e.key === " " || e.key === "ArrowRight") holding.current = false;
    };
    window.addEventListener("keydown", down);
    window.addEventListener("keyup", up);
    return () => { window.removeEventListener("keydown", down); window.removeEventListener("keyup", up); };
  }, [claimStyle, finish]);

  const C = 2 * Math.PI * 105;
  const off = C * (1 - prog);

  return (
    <div className="screen claim"
      onPointerDown={() => { if (claimStyle === "pinch") finish(); else holding.current = true; }}
      onPointerUp={() => { holding.current = false; }}
      onPointerLeave={() => { holding.current = false; }}>
      <div className="bloom" style={{ width: 420, height: 420, top: 90, left: 90, opacity: 0.5 + prog * 0.6 }} />

      <div className="patch-stage">
        <div className="hold-ring">
          <svg viewBox="0 0 230 230">
            <circle className="hr-track" cx="115" cy="115" r="105" strokeWidth="2" />
            <circle className="hr-val" cx="115" cy="115" r="105" strokeWidth="3"
              strokeDasharray={C} strokeDashoffset={off} />
          </svg>
        </div>
        <div className={done ? "materialize" : ""} style={{ transform: `scale(${0.82 + prog * 0.18})`, transition: "transform .1s linear" }}>
          <Patch2 mark={site.mark} size={150} shape={shape} earned={prog > 0.02} accent={site.accent} />
        </div>
      </div>

      <div className="prompt">
        {done ? (
          <>
            <div className="big glow-text">Patch claimed</div>
            <div className="sub">{site.name} &middot; {site.year}</div>
            {site.secret && <div className="secret-flash">✦ Secret location unlocked</div>}
          </>
        ) : claimStyle === "hold" ? (
          <>
            <div className="big">You've arrived at {site.name}</div>
            <div className="pinch-glyph">✦ Pinch &amp; hold to develop the patch</div>
          </>
        ) : (
          <>
            <div className="big">You've arrived at {site.name}</div>
            <div className="pinch-glyph">✦ Select to claim the patch</div>
          </>
        )}
      </div>
    </div>
  );
}

// ============================================================ DETAIL
function DetailScreen({ site, shape, justEarned, collected, isLast, total, onNavigate, onWatch, onHome, onPassport, onFinish, onSecret }) {
  const trailTotal = total || window.TRAIL.length;
  const scrollRef = React.useRef(null);
  const [atBottom, setAtBottom] = React.useState(false);
  const onScroll = (e) => {
    const el = e.currentTarget;
    setAtBottom(el.scrollTop + el.clientHeight >= el.scrollHeight - 4);
  };
  React.useEffect(() => {
    const el = scrollRef.current;
    if (el) setAtBottom(el.scrollHeight <= el.clientHeight + 4);
  }, [site]);

  return (
    <div className="screen detail" data-back-on-left>
      <div className="bloom" style={{ width: 300, height: 200, top: -40, left: 150, opacity: 0.45 }} />
      <div className="statusbar">
        <span className="label">{site.n} / 0{trailTotal}</span>
        <span className={"dt-chip" + (collected ? " done" : "")}>
          {collected ? "✓ Collected" : "Not yet collected"}
        </span>
      </div>

      <div className={"dt-hero" + (site.photo ? "" : " no-photo")}>
        {site.photo && (
          <img
            key={site.id}
            className="dt-hero-photo"
            src={site.photo}
            alt={site.name}
            loading="lazy"
            onError={(e) => { e.currentTarget.style.display = "none"; }}
          />
        )}
        <div className="dt-hero-content">
          <div className={justEarned ? "materialize" : ""}>
            <Patch2 mark={site.mark} size={62} shape={shape} earned={collected || justEarned} accent={site.accent} />
          </div>
          <div className="dt-meta">
            <div className="yr glow-text">{site.year}</div>
            <div className="nm">{site.name}</div>
            <div className="ad">{site.place}</div>
          </div>
        </div>
      </div>

      <div className="dt-scroll-wrap">
        <div className="dt-scroll focusable" data-focus data-autofocus data-scroll
          ref={scrollRef} onScroll={onScroll}>
          {collected && site.secret && (
            <div className={"secret-teaser" + (justEarned ? " reveal" : "")} onClick={() => onSecret(site)}>
              <span className="st-head">✦ Secret location revealed</span>
              <span className="st-name">{site.secret.name}<span className="st-go"> →</span></span>
              <span className="st-sub">{site.secret.place} &middot; <span className="st-hint-desktop">find it in your trail list</span><span className="st-hint-mobile">tap to open</span></span>
            </div>
          )}
          {site.visit && (
            <div className={"visit-card" + (site.visit.tone === "warn" ? " warn" : "")}>
              <span className="visit-ic"><Icon2 name={site.visit.tone === "warn" ? "alert" : "clock"} size={17} /></span>
              <div className="visit-body">
                <div className="visit-label">{site.visit.label}</div>
                {site.visit.lines.map((l, i) => <div className="visit-line" key={i}>{l}</div>)}
              </div>
            </div>
          )}
          <p className="lede">{site.lede}</p>
          {site.history.map((p, i) => <p className="hpar" key={i}>{p}</p>)}
          <div className="quote">{site.quote.t}<cite>{site.quote.c}</cite></div>
          <div className="src">
            <div className="src-label">Sources</div>
            {site.sources.map((s, i) => <div className="src-item" key={i}>{s}</div>)}
            <div className="src-note">{site.sourceNote || window.SOURCE_NOTE}</div>
          </div>
        </div>
        <div className={"scroll-cue" + (atBottom ? " hidden" : "")} aria-hidden="true">
          <Icon2 name="chevron" size={18} />
        </div>
      </div>

      {site.video && (
        <button className="watch-bar focusable" data-focus onClick={() => onWatch(site)}>
          <span className="wb-play"><Icon2 name="play" size={14} /></span>
          <span className="wb-text">
            <span className="wb-title">Watch in depth: {site.video.title}</span>
            <span className="wb-meta">{site.video.channel} &middot; {site.video.year}</span>
          </span>
        </button>
      )}

      <div className="detail-foot">
        <button className="btn focusable" data-focus data-back onClick={onHome}><Icon2 name="back" /> Back</button>
        {!collected
          ? <button className="btn primary focusable" data-focus onClick={onNavigate}><Icon2 name="nav" /> Navigate</button>
          : <button className="btn focusable" data-focus onClick={onPassport}><Icon2 name="grid" /> Passport</button>}
      </div>
    </div>
  );
}

// ============================================================ PASSPORT
function PassportScreen({ collected, shape, onOpen, onBack }) {
  const all = window.TRAIL_ALL;
  const trail = all.filter((s) => !s.wwdcYear);
  const wwdc = all.filter((s) => s.wwdcYear).sort((a, b) => a.wwdcYear - b.wwdcYear);
  const liveWwdcId = (window.TRAIL.find((s) => s.wwdcYear) || {}).id;
  const trailDone = trail.filter((s) => collected.includes(s.id)).length;
  return (
    <div className="screen passport">
      <div className="bloom" style={{ width: 340, height: 180, top: -50, left: 130, opacity: 0.45 }} />
      <div className="statusbar">
        <span className="label">Passport</span>
        <span className="label">{trailDone}/{trail.length} trail</span>
      </div>

      <div className="pp-scroll">
        <div className="pp-sec">Origin Trail</div>
        <div className="grid">
          {trail.map((s) => {
            const done = collected.includes(s.id);
            return (
              <div key={s.id} className={"pcard focusable" + (done ? " done" : "")} data-focus
                onClick={() => done && onOpen(s)}>
                <Patch2 mark={s.mark} size={58} shape={shape} earned={done} accent={s.accent} />
                <div className="pc-cap">{done ? s.name : "—"}</div>
              </div>
            );
          })}
        </div>

        <div className="pp-sec wwdc">WWDC · yearly patch</div>
        <div className="grid">
          {wwdc.map((s) => {
            const done = collected.includes(s.id);
            const live = s.id === liveWwdcId;
            const openable = done || live;
            return (
              <div key={s.id}
                className={"pcard wwdc focusable" + (done ? " done" : "") + (live && !done ? " live" : "")}
                data-focus onClick={() => openable && onOpen(s)}>
                <Patch2 mark={s.mark} size={58} shape={shape} earned={done} accent={s.accent} />
                <div className="pc-cap">{s.wwdcYear}{done ? "" : live ? " · live" : " · locked"}</div>
              </div>
            );
          })}
        </div>

        {window.osTrailLive && window.osTrailLive() && (window.OS_TRAIL || []).length > 0 && (
          <>
            <div className="pp-sec">macOS · California places</div>
            <div className="grid">
              {window.OS_TRAIL.map((s) => {
                const done = collected.includes(s.id);
                return (
                  <div key={s.id} className={"pcard focusable" + (done ? " done" : "")} data-focus
                    onClick={() => done && onOpen(s)}>
                    <Patch2 mark={s.mark} size={58} shape={shape} earned={done} accent={s.accent} />
                    <div className="pc-cap">{done ? s.name : "—"}</div>
                  </div>
                );
              })}
            </div>
          </>
        )}
      </div>

      <div className="home-foot" style={{ marginTop: 4 }}>
        <button className="btn focusable" data-focus data-back onClick={onBack}><Icon2 name="back" /> Back to trail</button>
      </div>
    </div>
  );
}

// ============================================================ COMPLETE
function CompleteScreen({ shape, onHome, collected = [] }) {
  const earned = window.TRAIL_ALL.filter((s) => collected.includes(s.id));
  return (
    <div className="screen complete" data-back-on-left>
      <div className="bloom" style={{ width: 460, height: 460, top: 60, left: 70, opacity: 0.7 }} />
      <div className="ttl glow-text" style={{ marginTop: 18 }}>All sites complete</div>
      <div className="msg">From a Los Altos garage to a glass ring in the orchard — you walked the whole arc of the valley's computing history.</div>
      <div className="cp-grid">
        {earned.map((s) => (
          <div key={s.id} className="cp-patch materialize">
            <Patch2 mark={s.mark} size={46} shape={shape} earned accent={s.accent} />
            <div className="cp-cap">{s.name}</div>
          </div>
        ))}
      </div>
      <div className="reward fade-up">★ {earned.length} patches earned</div>
      <div className="home-foot" style={{ marginTop: 14, maxWidth: 240 }}>
        <button className="btn focusable" data-focus data-autofocus data-back onClick={onHome}><Icon2 name="back" /> Trail</button>
      </div>
      <div className="disclaimer">An unofficial fan-made side quest — not affiliated with, endorsed by, or sponsored by Apple Inc. or WWDC.</div>
    </div>
  );
}

// ============================================================ WATCH
// Accepts an explicit video+name (e.g. a secret's video) or falls back to the
// active site's own video.
function WatchScreen({ site, video, name, onBack }) {
  const v = video || (site && site.video);
  const ttl = name || (site && site.name);
  const poster = `https://i.ytimg.com/vi/${v.id}/hqdefault.jpg`;
  return (
    <div className="screen watch detail" data-back-on-left>
      <div className="statusbar">
        <span className="label">Watch</span>
        <span className="label">{ttl}</span>
      </div>
      <div className="video-frame" style={{ backgroundImage: `url(${poster})` }}>
        <iframe
          src={`https://www.youtube-nocookie.com/embed/${v.id}?rel=0&modestbranding=1&autoplay=1&playsinline=1${v.start ? `&start=${v.start}` : ""}`}
          title={v.title} loading="lazy"
          allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
          allowFullScreen></iframe>
      </div>
      <div className="video-meta">
        <div className="vm-title">{v.title}</div>
        <div className="vm-sub">{v.channel} &middot; {v.year}</div>
        <div className="vm-src">Source &middot; {v.source}</div>
      </div>
      <div className="detail-foot">
        <button className="btn focusable" data-focus data-autofocus data-back onClick={onBack}><Icon2 name="back" /> Back</button>
      </div>
    </div>
  );
}

// ============================================================ VIDEO DRAWER (mobile)
// A bottom sheet that slides up and plays the video inline, instead of pushing a
// full screen. Tap the backdrop or Close to dismiss (which stops playback by
// unmounting the iframe).
function VideoDrawer({ video, name, onClose }) {
  const v = video;
  const poster = `https://i.ytimg.com/vi/${v.id}/hqdefault.jpg`;
  return (
    <div className="vd-overlay" onClick={onClose}>
      <div className="vd-sheet" onClick={(e) => e.stopPropagation()}>
        <div className="vd-handle" />
        <div className="video-frame" style={{ backgroundImage: `url(${poster})` }}>
          <iframe
            src={`https://www.youtube-nocookie.com/embed/${v.id}?rel=0&modestbranding=1&autoplay=1&playsinline=1${v.start ? `&start=${v.start}` : ""}`}
            title={v.title} loading="lazy"
            allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
            allowFullScreen></iframe>
        </div>
        <div className="video-meta">
          <div className="vm-title">{v.title}</div>
          <div className="vm-sub">{v.channel} &middot; {v.year}</div>
        </div>
        <button className="btn vd-close" onClick={onClose}><Icon2 name="back" /> Close</button>
      </div>
    </div>
  );
}

// ============================================================ SECRET
// A claimed site's hidden bonus location gets its own screen: the full fact,
// source, and an optional video. Reached from the home bonus row or the small
// teaser on the parent site's detail. There is no patch to earn here.
function SecretScreen({ secret, siteName, onBack, onWatch }) {
  const scrollRef = React.useRef(null);
  const [atBottom, setAtBottom] = React.useState(false);
  const onScroll = (e) => {
    const el = e.currentTarget;
    setAtBottom(el.scrollTop + el.clientHeight >= el.scrollHeight - 4);
  };
  React.useEffect(() => {
    const el = scrollRef.current;
    if (el) setAtBottom(el.scrollHeight <= el.clientHeight + 4);
  }, [secret]);

  return (
    <div className="screen detail secret-screen" data-back-on-left>
      <div className="bloom" style={{ width: 300, height: 200, top: -40, left: 150, opacity: 0.4 }} />
      <div className="statusbar">
        <span className="label">Secret location</span>
        <span className="dt-chip sx-chip">✦ Bonus &middot; No patch</span>
      </div>

      <div className="sx-hero">
        <div className="sx-glyph">✦</div>
        <div className="sx-meta">
          <div className="sx-name">{secret.name}</div>
          <div className="sx-place">{secret.place}</div>
        </div>
      </div>

      <div className="dt-scroll-wrap">
        <div className="dt-scroll focusable" data-focus data-autofocus data-scroll
          ref={scrollRef} onScroll={onScroll}>
          <div className="sx-unlock">Unlocked by claiming {siteName}. A bonus location — there's no patch to earn here.</div>
          <p className="lede">{secret.fact}</p>
          <div className="src">
            <div className="src-label">Source</div>
            <div className="src-item">{secret.source}</div>
          </div>
        </div>
        <div className={"scroll-cue" + (atBottom ? " hidden" : "")} aria-hidden="true">
          <Icon2 name="chevron" size={18} />
        </div>
      </div>

      {secret.video && (
        <button className="watch-bar focusable" data-focus onClick={onWatch}>
          <span className="wb-play"><Icon2 name="play" size={14} /></span>
          <span className="wb-text">
            <span className="wb-title">Watch in depth: {secret.video.title}</span>
            <span className="wb-meta">{secret.video.channel} &middot; {secret.video.year}</span>
          </span>
        </button>
      )}

      <div className="detail-foot">
        <button className="btn focusable" data-focus data-back onClick={onBack}><Icon2 name="back" /> Back</button>
      </div>
    </div>
  );
}

Object.assign(window, { ClaimScreen, DetailScreen, PassportScreen, CompleteScreen, WatchScreen, SecretScreen, VideoDrawer });
