// screens.jsx — Home + Radar screens. Presentational; receive state + callbacks.
// Shares Patch (window.Patch) and TRAIL (window.TRAIL).

const Patch = window.Patch;

// ---------- small primitive icons ----------
function Icon({ name, size = 16 }) {
  const p = { width: size, height: size, viewBox: "0 0 24 24", fill: "none",
    stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round",
    className: "gi" };
  switch (name) {
    case "back": return (<svg {...p}><polyline points="15 18 9 12 15 6" /></svg>);
    case "chevron": return (<svg {...p}><polyline points="6 9 12 15 18 9" /></svg>);
    case "play": return (<svg {...p}><polygon points="6 4 20 12 6 20" fill="currentColor" stroke="none" /></svg>);
    case "clock": return (<svg {...p}><circle cx="12" cy="12" r="9" /><polyline points="12 7 12 12 16 14" /></svg>);
    case "alert": return (<svg {...p}><polygon points="12 3 22 20 2 20" /><line x1="12" y1="9" x2="12" y2="14" /><circle cx="12" cy="17.5" r="0.6" fill="currentColor" stroke="none" /></svg>);
    case "external": return (<svg {...p}><path d="M14 4h6v6" /><line x1="20" y1="4" x2="11" y2="13" /><path d="M19 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h5" /></svg>);
    case "map": return (<svg {...p}><polygon points="3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21" /><line x1="9" y1="3" x2="9" y2="18" /><line x1="15" y1="6" x2="15" y2="21" /></svg>);
    case "nav": return (<svg {...p}><line x1="5" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" /></svg>);
    case "compass": return (<svg {...p}><circle cx="12" cy="12" r="9" /><polygon points="16 8 11 11 8 16 13 13 16 8" fill="currentColor" stroke="none" /></svg>);
    case "grid": return (<svg {...p}><rect x="4" y="4" width="6" height="6" /><rect x="14" y="4" width="6" height="6" /><rect x="4" y="14" width="6" height="6" /><rect x="14" y="14" width="6" height="6" /></svg>);
    case "check": return (<svg {...p}><polyline points="20 6 9 17 4 12" /></svg>);
    case "book": return (<svg {...p}><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z" /><line x1="9" y1="7" x2="15" y2="7" /></svg>);
    case "star": return (<svg {...p}><polygon points="12 3 14.6 9 21 9.5 16 13.8 17.6 20 12 16.5 6.4 20 8 13.8 3 9.5 9.4 9" /></svg>);
    case "settings": return (<svg {...p}><line x1="4" y1="8" x2="20" y2="8" /><line x1="4" y1="16" x2="20" y2="16" /><circle cx="9" cy="8" r="2.4" fill="currentColor" stroke="none" /><circle cx="15" cy="16" r="2.4" fill="currentColor" stroke="none" /></svg>);
    case "peak": return (<svg {...p}><path d="M3 20 L9 9 L13 15 L16 10 L21 20 Z" /></svg>);
    default: return null;
  }
}

function fmtDist(mi) {
  if (mi <= 0) return { v: "0", u: "ft" };
  if (mi < 0.19) return { v: String(Math.round(mi * 5280 / 10) * 10), u: "ft" };
  return { v: mi.toFixed(1), u: "mi" };
}

// Claim-radius copy: metres up to 1 km, then km (the OS Trail's natural
// landmarks are claimed from a viewpoint, so their radii are much larger).
function fmtRadius(m) {
  if (m >= 1000) { const k = m / 1000; return (Number.isInteger(k) ? k : k.toFixed(1)) + " km"; }
  return m + " m";
}

// Bearing from the user's real position to a target site. 0 = north.
function bearing(from, to) {
  const dy = to.lat - from.lat, dx = (to.lng - from.lng) * Math.cos(from.lat * Math.PI / 180);
  let a = Math.atan2(dx, dy) * 180 / Math.PI;
  return (a + 360) % 360;
}

// ============================================================ HOME
function HomeScreen({ collected, allDone, shape, onSite, onSecret, onPassport, onOsTrail, bingoLive, onBingo, showDebug, onDebug }) {
  const total = window.TRAIL.length;
  const got = collected.length;
  const C = 2 * Math.PI * 34;
  const off = C * (1 - got / total);
  const { user, live } = window.useUserLocation();
  // attach distance, then order: uncollected nearest-first, collected after
  const rows = window.TRAIL.map((s) => ({ s, done: collected.includes(s.id), dm: window.geoDistM(user, s) }))
    .sort((a, b) => (a.done !== b.done ? (a.done ? 1 : -1) : a.dm - b.dm));
  const nextId = rows.find((r) => !r.done)?.s.id; // nearest uncollected = next up
  // Unlocked secret locations: shown as bonus entries once the parent patch is
  // claimed. They are NOT patches — visiting them earns nothing (not in TRAIL).
  const secretRows = window.TRAIL
    .filter((s) => collected.includes(s.id) && s.secret)
    .map((s) => ({ s, sec: s.secret, dm: window.geoDistM(user, s.secret) }))
    .sort((a, b) => a.dm - b.dm);
  return (
    <div className="screen">
      <div className="bloom" style={{ width: 360, height: 200, top: -70, left: 120 }} />
      <div className="home-top">
        <div>
          <div className="kicker glow-text">Origin Trail</div>
          <div className="title" style={{ marginTop: 8 }}>Apple<br />in the Valley</div>
          <div className="label" style={{ marginTop: 12 }}>San Francisco Bay Area &middot; Silicon Valley</div>
        </div>
        <div className="progress-ring">
          <svg viewBox="0 0 78 78">
            <circle className="pr-track" cx="39" cy="39" r="34" strokeWidth="3" />
            <circle className="pr-val" cx="39" cy="39" r="34" strokeWidth="3"
              strokeDasharray={C} strokeDashoffset={off} />
          </svg>
          <div className="pr-num"><b>{got}<span style={{ color: "var(--ink-faint)", fontSize: 14 }}>/{total}</span></b><span>Patches</span></div>
        </div>
      </div>

      <div className="home-subhead">
        <span className="label">{allDone ? "Trail complete" : "Nearest first"}</span>
        <span className="label">{live ? "● your location" : "○ sim. location"}</span>
      </div>

      <div className="site-list">
        {rows.map(({ s, done, dm }, i) => {
          const ready = s.id === nextId;
          const d = window.geoMiles(dm);
          const region = s.place.split(",").slice(-2, -1)[0].trim().toUpperCase();
          return (
            <div key={s.id} className={"site-row focusable" + (done ? " done" : "")}
              data-focus data-nav-zone="list" data-autofocus={i === 0 ? true : undefined} onClick={() => onSite(s)}>
              <div className="idx"><Patch mark={s.mark} size={30} shape={shape} earned={done} accent={s.accent} /></div>
              <div className="site-info">
                <div className="nm">{s.name}</div>
                <div className="mt">{done ? "COLLECTED · " + s.year : (ready ? "NEXT UP · " + region : region)}</div>
              </div>
              <div className="site-dist">{d.v}<span>{d.u}</span></div>
              <div className={"dot " + (done ? "done" : ready ? "ready" : "locked")} />
            </div>
          );
        })}

        {secretRows.length > 0 && (
          <div className="list-divider">Bonus &middot; Secret locations</div>
        )}
        {secretRows.map(({ s, sec, dm }) => {
          const d = window.geoMiles(dm);
          const region = sec.place.split(",").slice(-2).join(",").trim().toUpperCase();
          return (
            <div key={"sec-" + s.id} className="site-row bonus focusable"
              data-focus data-nav-zone="list" onClick={() => onSecret(s)}>
              <div className="idx bonus-glyph">✦</div>
              <div className="site-info">
                <div className="nm">{sec.name}</div>
                <div className="mt">{region} &middot; NO PATCH</div>
              </div>
              <div className="site-dist">{d.v}<span>{d.u}</span></div>
              <div className="dot bonus" />
            </div>
          );
        })}
      </div>

      <div className="home-foot">
        {showDebug && (
          <button className="btn focusable" data-focus onClick={onDebug}>
            <Icon name="settings" /> Debug
          </button>
        )}
        <button className="btn focusable" data-focus onClick={onPassport}>
          <Icon name="grid" /> Passport
        </button>
        {onOsTrail && (
          <button className="btn focusable" data-focus onClick={onOsTrail}>
            <Icon name="peak" /> OS Trail
          </button>
        )}
        {bingoLive && (
          <button className="btn primary focusable bingo-cta" data-focus onClick={onBingo}>
            <Icon name="star" /> Bingo
          </button>
        )}
      </div>
      <div className="home-disclaimer">Unofficial fan side quest · not affiliated with Apple or WWDC</div>
    </div>
  );
}

// ============================================================ RADAR
// Default: must be physically within this many metres of the site to claim its
// patch. A site may widen it via `site.claimRadius` — the OS Trail's natural
// landmarks (an offshore break, a lake, a 14er) are claimed from a viewpoint, so
// they carry a much larger radius than the Origin Trail's street addresses.
const CLAIM_RADIUS_M = 75;

function RadarScreen({ site, onArrived, onBack }) {
  const { user, live } = window.useUserLocation();
  const [wob, setWob] = React.useState(0);

  // Real distance + bearing from the live GPS fix. No simulated approach.
  const distM = window.geoDistM(user, site);
  const brg = bearing(user, site);
  const claimRadius = site.claimRadius || CLAIM_RADIUS_M;
  const arrived = live && distM <= claimRadius;

  React.useEffect(() => {
    if (arrived) return;
    const id = setInterval(() => setWob((Math.random() - 0.5) * 7), 600);
    return () => clearInterval(id);
  }, [arrived]);

  const d = window.geoMiles(distM);
  // Blip pulls toward center as you approach; pinned to the rim when far or
  // while we have no real fix yet (norm clamps at ~0.8 km out).
  const norm = Math.min(1, distM / 800);
  const rad = arrived ? 16 : Math.min(120, 28 + norm * 92);
  const ang = (brg + wob) * Math.PI / 180;
  const tx = Math.sin(ang) * rad, ty = -Math.cos(ang) * rad;

  const status = arrived ? "Arrived" : live ? "Navigating" : "Locating…";

  return (
    <div className="screen">
      <div className="bloom" style={{ width: 380, height: 380, top: 90, left: 110 }} />
      <div className="statusbar">
        <span className="label">{status}</span>
      </div>
      <div className="radar-name">
        <div className="kicker glow-text">{site.name}</div>
      </div>

      <div className="radar-wrap">
        <div className="radar">
          <div className="ring" /><div className="ring r2" /><div className="ring r3" />
          {!arrived && <div className="sweep" />}
          {live && <div className="heading-needle" style={{ transform: `rotate(${brg + wob}deg)` }} />}
          {live && (
            <div className="target" style={{ transform: `translate(${tx}px, ${ty}px)` }}>
              <div className="blip"><Patch mark={site.mark} size={arrived ? 46 : 34} shape="hex" accent={site.accent} /></div>
            </div>
          )}
          <div className="you" />
        </div>

        <div className="radar-read">
          {arrived ? (
            <>
              <div className="dist glow-text">HERE</div>
              <div className="sub">You've reached the site</div>
            </>
          ) : live ? (
            <>
              <div className="dist glow-text">{d.v}<small>{d.u}</small></div>
              <div className="sub">Bearing {Math.round(brg)}&deg; &middot; get within {fmtRadius(claimRadius)} to claim</div>
            </>
          ) : (
            <>
              <div className="dist glow-text">&mdash;</div>
              <div className="sub">Waiting for GPS &mdash; enable location to claim</div>
            </>
          )}
        </div>
      </div>

      <div className="home-foot">
        {arrived ? (
          <>
            <button className="btn focusable" data-focus data-back onClick={onBack}>
              <Icon name="back" /> Back
            </button>
            <button className="btn primary focusable" data-focus data-autofocus onClick={onArrived}>
              <Icon name="nav" /> Claim patch
            </button>
          </>
        ) : (
          <button className="btn focusable" data-focus data-autofocus data-back onClick={onBack}>
            <Icon name="back" /> End navigation
          </button>
        )}
      </div>
    </div>
  );
}

window.HomeScreen = HomeScreen;
window.RadarScreen = RadarScreen;
window.RadarIcon = Icon; // expose for reuse
window.Icon = Icon;
window.fmtDist = fmtDist;
