// screens-map.jsx — MapScreen: a simple, stylized California map of the OS Trail.
//
// The OS Trail's places (Half Moon Bay → Tahoe → Big Sur) span the whole state,
// so they're drawn over a simplified California silhouette. The outline is
// hand-traced from real lat/lng points and projected with the SAME projector as
// the site pins, so pins always land in the right place relative to the coast.
// Per CLAUDE.md, a claimed site's `secret` shows as a display-only amber pin,
// clamped to the frame so far-off spots don't distort it. All geometry is
// luminous strokes on black to suit the waveguide display.

// ---- map bounds (frame the state with a little padding) ----
const CA_BOUNDS = { minLat: 32.3, maxLat: 42.1, minLng: -124.6, maxLng: -114.0 };

// ---- simplified California outline (coast N→S, then SE + E borders back up) ----
const CA_OUTLINE = [
  [42.00,-124.21],[41.74,-124.20],[40.80,-124.16],[39.55,-123.77],[38.95,-123.73],
  [38.32,-123.07],[37.81,-122.52],[37.50,-122.50],[36.96,-122.02],[36.62,-121.90],
  [36.27,-121.85],[35.66,-121.28],[35.16,-120.74],[34.45,-120.47],[34.42,-119.70],
  [34.02,-118.50],[33.74,-118.19],[33.55,-117.78],[32.85,-117.26],[32.53,-117.12],
  [32.62,-116.10],[32.72,-114.72],[33.43,-114.52],[34.26,-114.14],[34.78,-114.43],
  [35.00,-114.63],[39.00,-120.00],[42.00,-120.00],
];

// Build a projector: equirectangular, longitude compressed by cos(midLat) so the
// shape isn't stretched. Fixed VW; VH derives from the bounds' true aspect.
function makeProjector(B) {
  const midLat = (B.minLat + B.maxLat) / 2;
  const lngScale = Math.cos(midLat * Math.PI / 180);
  const geoW = (B.maxLng - B.minLng) * lngScale;
  const geoH = (B.maxLat - B.minLat);
  const VW = 1000;
  const VH = Math.round(VW * geoH / geoW);
  const project = (lat, lng) => [
    (lng - B.minLng) / (B.maxLng - B.minLng) * VW,
    (B.maxLat - lat) / (B.maxLat - B.minLat) * VH,
  ];
  return { VW, VH, project };
}

const ptsToStr = (pts, proj) => pts.map(([la, ln]) => proj.project(la, ln).join(",")).join(" ");
const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));

function MapScreen({ sites, collected, shape, title, onSite, onBack }) {
  const Icon = window.Icon;
  const { user } = window.useUserLocation();
  const proj = React.useMemo(() => makeProjector(CA_BOUNDS), []);
  const { VW, VH, project } = proj;

  // attach collected + distance; next-up = nearest uncollected
  const rows = sites.map((s) => ({ s, done: collected.includes(s.id), dm: window.geoDistM(user, s) }));
  const nextId = rows.filter((r) => !r.done).sort((a, b) => a.dm - b.dm)[0]?.s.id;
  const startIdx = Math.max(0, sites.findIndex((s) => s.id === nextId));
  const [active, setActive] = React.useState(startIdx);

  // trail path, in definition order (the walking sequence)
  const trailStr = ptsToStr(sites.map((s) => [s.lat, s.lng]), proj);

  // secret pins: claimed sites only, display-only, clamped into the frame
  const pad = VW * 0.04;
  const secrets = rows
    .filter((r) => r.done && r.s.secret)
    .map((r) => {
      const [x, y] = project(r.s.secret.lat, r.s.secret.lng);
      return { id: r.s.id, x: clamp(x, pad, VW - pad), y: clamp(y, pad, VH - pad) };
    });

  const a = rows[active] || rows[0];
  const dist = a ? window.geoMiles(a.dm) : { v: "—", u: "" };
  const status = !a ? "" : a.done ? "COLLECTED" : a.s.id === nextId ? "NEXT UP" : "ON TRAIL";

  // Size the stage to *contain* the map's aspect ratio inside the available box.
  // Doing this in JS (vs CSS aspect-ratio) avoids a flexbox overflow where the
  // ratio forces an intrinsic height taller than the fixed 600px screen.
  const wrapRef = React.useRef(null);
  const [stage, setStage] = React.useState({ w: 0, h: 0 });
  React.useLayoutEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const measure = () => {
      const aw = el.clientWidth, ah = el.clientHeight;
      if (!aw || !ah) return;
      const sc = Math.min(aw / VW, ah / VH);
      setStage({ w: Math.round(VW * sc), h: Math.round(VH * sc) });
    };
    measure();
    window.addEventListener("resize", measure);
    return () => window.removeEventListener("resize", measure);
  }, [VW, VH]);

  return (
    <div className="screen map-screen">
      <div className="bloom" style={{ width: 360, height: 200, top: -70, left: 120 }} />
      <div className="home-top">
        <div>
          <div className="kicker glow-text">{title}</div>
          <div className="title" style={{ marginTop: 8 }}>On the map</div>
          <div className="label" style={{ marginTop: 12 }}>California · the places behind macOS</div>
        </div>
      </div>

      <div className="map-wrap" ref={wrapRef}>
        <div className="map-stage" style={{ width: stage.w, height: stage.h }}>
          <svg className="map-svg" viewBox={`0 0 ${VW} ${VH}`} preserveAspectRatio="xMidYMid meet">
            <polygon className="map-land" points={ptsToStr(CA_OUTLINE, proj)} />
            <polyline className="map-trail" points={trailStr} />
            {secrets.map((sec) => (
              <circle key={"sec-" + sec.id} className="map-secret" cx={sec.x} cy={sec.y} r="7" />
            ))}
          </svg>

          {sites.map((s, i) => {
            const done = rows[i].done;
            const ready = s.id === nextId;
            const [x, y] = project(s.lat, s.lng);
            const dotStyle = done && s.accent
              ? { background: s.accent, borderColor: s.accent, boxShadow: `0 0 calc(8px*var(--gi)) ${s.accent}` }
              : undefined;
            return (
              <button key={s.id}
                className={"map-pin focusable" + (done ? " done" : "") + (ready ? " ready" : "")}
                style={{ left: (x / VW * 100) + "%", top: (y / VH * 100) + "%" }}
                data-focus data-autofocus={i === startIdx ? true : undefined}
                onFocus={() => setActive(i)} onMouseEnter={() => setActive(i)}
                onClick={() => onSite(s)}>
                <span className="map-dot" style={dotStyle} />
                <span className="map-plabel">{s.name}</span>
              </button>
            );
          })}
        </div>
      </div>

      <div className="map-caption">
        <div className="map-cap-name">{a ? a.s.name : "—"}</div>
        <div className="label">{status}{a ? " · " + dist.v + " " + dist.u : ""}</div>
      </div>

      <div className="home-foot">
        <button className="btn focusable" data-focus data-back onClick={onBack}>
          <Icon name="back" /> {title}
        </button>
      </div>
      <div className="home-disclaimer">Stylized map · pins are approximate</div>
    </div>
  );
}

window.MapScreen = MapScreen;
