/* ============================================================
   ROOY · 02 准备出发
   ───────────────────────────────────────────────────────────
   需求：当日开滑前的雪场上下文 + ROOY 一句建议 + 出发按钮。
   地形图打底把用户放回雪场空间；天气收进悬浮卡。

   结构：全屏 basemap（地形层 → 静音 scrim → 定位信息层）→
   日期 + Zermatt title + 传感器按钮 → 天气卡（−7° italic +
   SunGlyph / hairline / 3 列 CCond）→ ROOY 白卡滑行建议 →
   SlideToStart（pinned 拇指区）。

   accent budget：data 蓝 1（地图定位点）；rooy 3（传感器 pip + 滑行建议 pill +
   白卡 "40° 立刃"，原 gold 已改 rooy）；gold 0。主导 = ink。
   italic 锚 = 天气 −7°。

   交互：滑动到尾段提交，进入 03b 自由模式（默认）。**不是**
   "长按 600ms"（早期方案，已弃用 —— 戴手套滑动比按住准）。

   非显然的设计决定：地形层压一层 bg 60% 的静音 scrim——出发前
   地图是"未激活"底图，与 03b/03c 滑行中的全强度地图形成状态区
   分，也让卡片内容前置；定位点 + 缆车站画在 scrim 之上保持清晰
   （这屏地图唯一要回答"我在哪"）。内容白卡（天气 / 滑行建议）
   对齐 01q 主屏白卡：Shadow.cardSoft + 左右 20；建议卡垂直 16，
   天气卡因含 76pt 大字垂直放到 20；按钮与交互层（传感器钮 /
   SlideToStart）浮在地图上仍用 Shadow.lift。卡内 hairline 分隔
   HANDOFF 允许的双模块例外。地图
   上没画建议路线——练什么由白卡文字承担。basemap 色值与
   ski-b.jsx 一致（冷调雪面浅灰蓝，one-off 不入 token）。
   ============================================================ */

function PreSessionScreenC({ onNav }) {
  return (
    <div style={{
      height: '100%', display: 'flex', flexDirection: 'column',
      background: '#E8ECF1', position: 'relative', color: R.ink, ...T.subhead,
    }}>

      {/* basemap — 全屏 844，等高线延伸到底；出发前无滑行轨迹，
          只有缆车虚线 + Furi 站 + 出发点定位 */}
      <div style={{
        position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
        overflow: 'hidden',
      }}>
        <svg width="100%" height="100%" viewBox="0 0 390 844" preserveAspectRatio="xMidYMin slice"
             style={{ display: 'block' }}>
          <defs>
            <linearGradient id="presession-c-mp" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="844">
              <stop offset="0%"    stopColor="#F4F6F9"/>
              <stop offset="50%"   stopColor="#E8ECF1"/>
              <stop offset="100%"  stopColor="#E8ECF1"/>
            </linearGradient>
          </defs>
          <rect width="390" height="844" fill="url(#presession-c-mp)"/>

          {Array.from({ length: 27 }).map((_, i) => {
            const y = 18 + i * 30;
            const amp = 24 + (i % 4) * 9;
            return (
              <path key={i}
                d={`M -40 ${y} Q 80 ${y - amp} 180 ${y} T 400 ${y - amp / 2}`}
                fill="none" stroke="rgba(14,17,22,0.07)" strokeWidth="0.8"/>
            );
          })}
          {Array.from({ length: 7 }).map((_, i) => {
            const y = 65 + i * 120;
            return (
              <path key={i}
                d={`M -40 ${y} Q 80 ${y - 28} 180 ${y} T 400 ${y - 14}`}
                fill="none" stroke="rgba(14,17,22,0.14)" strokeWidth="1.2"/>
            );
          })}

          {/* 海拔标注 — 与 03b 同刻度（120px / 200M）；被卡片盖住的
              保留不删，露出的是下方 1400 M 一条 */}
          <text x="100" y="63"  style={{ ...T.caption2, fill: 'rgba(14,17,22,0.42)' }}>2400 M</text>
          <text x="100" y="303" style={{ ...T.caption2, fill: 'rgba(14,17,22,0.42)' }}>2000 M</text>
          <text x="100" y="543" style={{ ...T.caption2, fill: 'rgba(14,17,22,0.42)' }}>1600 M</text>
          <text x="24"  y="640" style={{ ...T.caption2, fill: 'rgba(14,17,22,0.42)' }}>1400 M</text>

          {/* 缆车虚线 — 从山脚站向上山方向 */}
          <path d="M 150 632 L 250 70" stroke="rgba(14,17,22,0.4)" strokeWidth="1.4" strokeDasharray="3 4" strokeLinecap="round"/>
        </svg>

        {/* 静音 scrim — 出发前地图是"未激活"底图：把地形推远、让
            卡片内容前置，也与 03b/03c 滑行中的全强度地图形成状态
            区分。定位点 + 缆车站画在 scrim 之上保持清晰。 */}
        <div style={{
          position: 'absolute', inset: 0,
          background: 'color-mix(in srgb, var(--r-bg) 60%, transparent)',
        }}/>

        {/* info 层 — 定位点与缆车站，浮在 scrim 上 */}
        <svg width="100%" height="100%" viewBox="0 0 390 844" preserveAspectRatio="xMidYMin slice"
             style={{ position: 'absolute', inset: 0 }}>
          {/* Furi 缆车站 glyph + label */}
          <g transform="translate(178 596)">
            <path d="M 0 8 L 6 0 L 12 8 Z" fill="rgba(14,17,22,0.42)"/>
            <rect x="2" y="8" width="8" height="5" fill="rgba(14,17,22,0.42)"/>
            <text x="18" y="11" style={{ ...T.caption2, fill: 'rgba(14,17,22,0.55)' }}>Furi 缆车站</text>
          </g>

          {/* 出发点定位 — 03b 同款 data 蓝三环，"你在缆车站" */}
          <circle cx="150" cy="632" r="18" fill="var(--r-data)" fillOpacity=".14"/>
          <circle cx="150" cy="632" r="10" fill="var(--r-data)" fillOpacity=".30"/>
          <circle cx="150" cy="632" r="5.5" fill="var(--r-data)"/>
          <circle cx="150" cy="632" r="5.5" fill="none" stroke="#fff" strokeWidth="1.5"/>
        </svg>
      </div>

      <StatusBar/>

      <div style={{ flex: 1, position: 'relative' }}>

        {/* ── Header — 传感器按钮浮在地图上加 lift ── */}
        <div style={{ padding: '8px 20px 0', display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
          <div style={{ paddingTop: 4 }}>
            <p style={{ ...T.footnote, color: R.ink3, marginBottom: 4 }}>5 月 3 日 · 周五 · 瑞士阿尔卑斯</p>
            <h1 style={{ ...T.title, color: R.ink }}>Zermatt</h1>
          </div>
          <button onClick={() => onNav && onNav('pairing-connected')} style={{
            width: 44, height: 44, borderRadius: '50%',
            background: R.card, border: 'none', cursor: 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative',
            marginTop: 12,
            boxShadow: Shadow.lift,
          }}>
            <SensorGlyph color={R.ink}/>
            <span style={{
              position: 'absolute', bottom: -1, right: -1,
              width: 12, height: 12, borderRadius: '50%',
              background: R.rooy, border: `2px solid ${R.bg}`,
            }}/>
          </button>
        </div>

        <div style={{ height: 14 }}/>

        {/* ── 天气卡 — 悬浮白卡。含 76pt 大字，垂直 padding 20 比内容卡多一档呼吸 ── */}
        <div style={{
          margin: '0 16px', borderRadius: B.cardL, padding: '20px 20px',
          background: R.card,
          boxShadow: Shadow.cardSoft,   /* 内容白卡对齐 01q 主屏（cardSoft）；按钮/交互层仍用 lift */
        }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 5 }}>
              <span style={{ ...N.italic, fontSize: 76, color: R.ink, lineHeight: 0.85 }}>−7</span>
              <span style={{ ...N.italic, fontSize: 34, color: R.ink, paddingBottom: 5 }}>°</span>
            </div>
            <SunGlyph size={56} color={R.ink3}/>
          </div>

          <div style={{
            marginTop: 16, paddingTop: 16, borderTop: `0.5px solid ${R.hair}`,
            display: 'flex', justifyContent: 'space-between',
          }}>
            <CCond l="新雪"     v="12" u="cm"/>
            <CCond l="开放雪道" v="38" u="/ 52"/>
            <CCond l="风速"     v="12" u="km/h"/>
          </div>
        </div>

        {/* 28：白卡与天气卡拉开一档，构图重心下移，露出更多地图 */}
        <div style={{ height: 28 }}/>

        {/* ── 建议白卡 · 滑行建议（原黑卡；白底后 TopoLines 白描线不可见，移除）── */}
        <div style={{
          margin: '0 16px', borderRadius: B.cardL, padding: '16px 20px',
          background: R.card, color: R.ink,
          position: 'relative', overflow: 'hidden',
          boxShadow: Shadow.cardSoft,
        }}>
          <div style={{ position: 'relative' }}>
            <StatusBadge tone="rooy">滑行建议</StatusBadge>

            <p style={{ ...T.h1, color: R.ink, marginTop: 14 }}>
              把<span style={{ color: R.rooy, fontWeight: 700 }}> 40° 立刃 </span>变成本能
            </p>

            <p style={{ ...T.para, color: R.ink2, marginTop: 16 }}>
              上次你连三趟造出 40° 立刃，但右弯入弯还有点犹豫。
              <span style={{ color: R.ink, fontWeight: 600 }}>今天 5 趟里凑 3 趟稳住，就成了。</span>
            </p>
          </div>
        </div>

      </div>

      {/* SlideToStart — pinned 拇指区 */}
      <div style={{
        position: 'absolute', left: '50%', bottom: 108,
        transform: 'translateX(-50%)',
        width: 280, zIndex: 40,
      }}>
        <SlideToStart onStart={() => onNav && onNav('ski')}/>
      </div>

      <TabBar active="ski" onTab={(tab) => onNav && onNav(tab)}/>
    </div>
  );
}

/* ── SlideToStart · sports-flavored swipe affordance ──────
   Chunky white thumb on a 76-tall ink track. Drag past 85% to
   commit; otherwise elastic-snaps back. Hint text track-centered,
   chevron pinned to track-right. `label` defaults to 开始滑行
   for fresh-session use; 02a (滑行结束) passes 继续滑行. */
function SlideToStart({ onStart, label = '开始滑行' }) {
  const [progress, setProgress] = React.useState(0);
  const [dragging, setDragging] = React.useState(false);
  const trackRef = React.useRef(null);
  const [maxTravel, setMaxTravel] = React.useState(0);
  const THUMB = 60;
  const PAD = 8;

  /* Auto-reset after commit so this layer's SlideToStart starts
     fresh next time the user returns (router pop-to-existing
     reuses the layer instance — without reset, thumb stays at
     progress=1 and the next swipe is dead).
     onStart goes through a latest-ref so an unstable callback
     identity from the parent (inline arrows re-create every render)
     doesn't re-trigger this effect after navigation — that caused
     a feedback loop where each onStart push re-rendered the parent,
     gave us a fresh onStart ref, re-scheduled, and pushed again. */
  const onStartRef = React.useRef(onStart);
  React.useEffect(() => { onStartRef.current = onStart; });
  React.useEffect(() => {
    if (progress < 1 || dragging) return;
    const tStart = setTimeout(() => onStartRef.current && onStartRef.current(), 280);
    const tReset = setTimeout(() => setProgress(0), 800);
    return () => { clearTimeout(tStart); clearTimeout(tReset); };
  }, [progress, dragging]);

  React.useLayoutEffect(() => {
    if (!trackRef.current) return;
    const measure = () => {
      if (trackRef.current) {
        setMaxTravel(Math.max(0, trackRef.current.offsetWidth - 2 * PAD - THUMB));
      }
    };
    measure();
    const ro = new ResizeObserver(measure);
    ro.observe(trackRef.current);
    return () => ro.disconnect();
  }, []);

  React.useEffect(() => {
    if (!dragging) return;
    const onMove = (e) => {
      const el = trackRef.current;
      if (!el) return;
      const rect = el.getBoundingClientRect();
      const scale = rect.width / el.offsetWidth || 1;
      const elementX = (e.clientX - rect.left) / scale;
      const home = PAD + THUMB / 2;
      const end = el.offsetWidth - PAD - THUMB / 2;
      const p = end > home ? (elementX - home) / (end - home) : 0;
      setProgress(Math.max(0, Math.min(1, p)));
    };
    const onUp = () => {
      setDragging(false);
      setProgress(p => p >= 0.85 ? 1 : 0);
    };
    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onUp);
    window.addEventListener('pointercancel', onUp);
    return () => {
      window.removeEventListener('pointermove', onMove);
      window.removeEventListener('pointerup', onUp);
      window.removeEventListener('pointercancel', onUp);
    };
  }, [dragging, onStart]);

  const onDown = (e) => {
    if (progress >= 1) return;
    e.preventDefault();
    setDragging(true);
  };

  return (
    <div ref={trackRef} style={{
      position: 'relative',
      width: '100%', height: 76,
      background: R.ink,
      borderRadius: 999,
      overflow: 'hidden',
      boxShadow: Shadow.lift,
      userSelect: 'none', touchAction: 'none',
    }}>
      <svg width="100%" height="100%" viewBox="0 0 280 76" preserveAspectRatio="none"
        style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
        <path d="M 60 62 L 130 14"
          stroke={R.hairD} strokeWidth="1.2" strokeLinecap="round"/>
        <path d="M 130 66 L 200 18"
          stroke={R.hairD} strokeWidth="1.0" strokeLinecap="round"/>
        <path d="M 195 60 L 250 22"
          stroke={R.hairD} strokeWidth="0.9" strokeLinecap="round"/>
      </svg>

      <div style={{
        position: 'absolute', inset: 0,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        color: '#fff', pointerEvents: 'none',
        opacity: Math.max(0, 1 - progress * 1.4),
        transition: dragging ? 'none' : 'opacity .32s ease',
      }}>
        <span style={{
          fontFamily: '"PingFang SC", -apple-system, system-ui, sans-serif',
          fontSize: 22, fontWeight: 700, letterSpacing: '-0.005em',
        }}>{label}</span>
      </div>

      <div style={{
        position: 'absolute', top: 0, right: 22, bottom: 0,
        display: 'flex', alignItems: 'center',
        pointerEvents: 'none',
        opacity: Math.max(0, 1 - progress * 1.4),
        transition: dragging ? 'none' : 'opacity .32s ease',
      }}>
        <svg width="22" height="14" viewBox="0 0 22 14">
          <path d="M2 2 L8 7 L2 12" stroke="#fff" strokeWidth="2"
            fill="none" strokeLinecap="round" strokeLinejoin="round" opacity="0.42"/>
          <path d="M11 2 L17 7 L11 12" stroke="#fff" strokeWidth="2"
            fill="none" strokeLinecap="round" strokeLinejoin="round" opacity="0.88"/>
        </svg>
      </div>

      <div onPointerDown={onDown} style={{
        position: 'absolute',
        top: PAD, left: PAD,
        width: THUMB, height: THUMB,
        borderRadius: '50%', background: '#fff',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        cursor: progress >= 1 ? 'default' : (dragging ? 'grabbing' : 'grab'),
        transform: `translateX(${progress * maxTravel}px)`,
        transition: dragging
          ? 'none'
          : 'transform .36s cubic-bezier(.32,.72,0,1)',
        boxShadow: Shadow.thumb,
        touchAction: 'none',
      }}>
        <svg width="16" height="20" viewBox="0 0 16 20">
          <path d="M2.5 1.5 L14 10 L2.5 18.5 Z" fill={R.ink}/>
        </svg>
      </div>
    </div>
  );
}

Object.assign(window, { PreSessionScreenC, SlideToStart });
