/* ============================================================
   ROOY · 16 / 17 / 18 配对三态
   ───────────────────────────────────────────────────────────
   需求：配对是 TASK 不是 destination —— bottom sheet 从 source 屏
   （设置 / pre-session / onboarding）弹出。

   状态完全由两枚传感器 disc 自身样貌承载（L/R 标识 = AirPods 引用），
   **不放进度条 / 步骤条**:
     idle       — hair2 ring + ink3 字 + 浅填色
     searching  — ink ring + ink 字 + 内部三段同心雷达波扩散
     found      — ink ring + R.data 蓝字（"我找到你了"）
     connected  — R.ink 实心 + 反白字 + 下方 ROOY 绿光点

   Accent budget: searching 0 · found 1 (R.data) · connected 1 (R.rooy)。
   配对成功"绑定 ROOY"的瞬间是这屏唯一 ROOY 绿出现的点。

   单 `<PairingSheet state>` 组件驱动三态；3 个 artboard 渲染同样的
   sheet 配不同 state，让 modal 架构可见。Sheet header drag handle
   承担下滑关闭，不放显式"完成"按钮。
   ============================================================ */

function PairingSearching({ onNav, embedded }) {
  return <PairingSheetScreen state="searching" onNav={onNav} embedded={embedded}/>;
}

function PairingFound({ onNav, embedded }) {
  return <PairingSheetScreen state="found" onNav={onNav} embedded={embedded}/>;
}

function PairingConnected({ onNav, embedded }) {
  return <PairingSheetScreen state="connected" onNav={onNav} embedded={embedded}/>;
}

/* PairingSheetScreen — full-phone artboard wrapper: light settings
   backdrop + scrim + PairingSheet. Each artboard fixes its initial
   state so we have discrete demos in the canvas.
   `embedded` (prototype): skip the StatusBar / settings peek / scrim
   and render PairingSheet so it fills the parent — the prototype
   router supplies a real source screen underneath + its own
   backdrop + slide-up transition. */
function PairingSheetScreen({ state, onNav, embedded }) {
  const [showDisconnect, setShowDisconnect] = React.useState(false);
  const disconnectSheet = showDisconnect && (
    <ActionSheet
      title="将断开左脚 + 右脚传感器，滑行数据会暂停记录"
      actions={[{ label: '断开连接', destructive: true, onClick: () => setShowDisconnect(false) }]}
      onCancel={() => setShowDisconnect(false)}
    />
  );
  if (embedded) {
    return (
      <>
        <PairingSheet state={state} embedded
          onConnect={() => onNav && onNav('pairing-connected')}
          onStart={() => onNav && onNav('presession')}
          onDisconnect={() => setShowDisconnect(true)}
        />
        {disconnectSheet}
      </>
    );
  }
  return (
    <>
      <div style={{
        height: '100%', display: 'flex', flexDirection: 'column',
        background: R.bg, color: R.ink, ...T.subhead,
        position: 'relative', overflow: 'hidden',
      }}>
        <StatusBar/>

        {/* Settings-page backdrop peek — gives context that the sheet
            sits on top of settings (the natural source). Pointer-events
            off so the sheet captures all input. */}
        <SettingsBackdrop/>

        {/* Scrim */}
        <div style={{
          position: 'absolute', inset: 0, zIndex: 5,
          background: Scrim.background,
          pointerEvents: 'none',
        }}/>

        <PairingSheet state={state}
          onConnect={() => onNav && onNav('pairing-connected')}
          onStart={() => onNav && onNav('presession')}
          onDisconnect={() => setShowDisconnect(true)}
        />
      </div>
      {disconnectSheet}
    </>
  );
}

/* SettingsBackdrop — a light approximation of the settings screen
   behind the sheet. We don't render the full SettingsScreen because
   it would compute heavy and look distracting under a scrim. Just
   header peek: title + profile row. */
function SettingsBackdrop() {
  return (
    <div style={{ flex: 1, padding: '4px 0 0' }}>
      <NavBar title="设置"/>
      <div style={{ padding: '6px 16px 0' }}>
        <div style={{
          background: R.card, borderRadius: B.cardL, padding: '14px 16px',
          display: 'flex', alignItems: 'center', gap: 14,
        }}>
          <UserAvatar size={56}/>
          <div style={{ flex: 1, minWidth: 0 }}>
            <p style={{ ...T.h2, color: R.ink }}>Yuki</p>
            <p style={{ ...T.footnote, color: R.ink3, marginTop: 4 }}>高阶滑手 滑雪发烧友</p>
          </div>
        </div>
      </div>
    </div>
  );
}

/* PairingSheet — bottom-sheet shell with state-driven content.
   In self-contained mode (Design Canvas) sheet height is fixed at
   600 so layout doesn't shift between states. In `embedded` mode
   (prototype router) the sheet fills its parent, since the parent
   is already sized to the sheet's footprint. */
function PairingSheet({ state, onConnect, onStart, onDisconnect, embedded }) {
  return (
    <div style={{
      ...(embedded
        ? { position: 'relative', width: '100%', height: '100%' }
        : { position: 'absolute', left: 0, right: 0, bottom: 0, height: 600 }),
      zIndex: 10,
      background: R.bg,
      borderTopLeftRadius: B.sheet, borderTopRightRadius: B.sheet,
      boxShadow: embedded ? 'none' : Shadow.sheet,
      display: 'flex', flexDirection: 'column',
      overflow: 'hidden',
    }}>
      {/* Drag handle */}
      <div style={{ display: 'flex', justifyContent: 'center', paddingTop: 10, flexShrink: 0 }}>
        <div style={{ width: 36, height: 5, borderRadius: 2.5, background: R.hair2 }}/>
      </div>

      {/* Title row — drag handle 已经承担"下滑关闭"信号, 不再放
          "完成"按钮 (chrome 冗余). 标题居中, "传感器" 跨三态保持稳定;
          state-specific copy (正在搜索 / 已发现 / 已连接) 仍在 disc
          下方, sheet header 不跳变. */}
      <div style={{
        height: 44, padding: '0 8px', flexShrink: 0,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>
        <p style={{ ...T.headline, color: R.ink }}>传感器</p>
      </div>

      {state === 'searching' && <PairingSearchingBody/>}
      {state === 'found' && <PairingFoundBody onConnect={onConnect}/>}
      {state === 'connected' && <PairingConnectedBody onStart={onStart} onDisconnect={onDisconnect}/>}
      <HomeIndicator/>
    </div>
  );
}

/* searching body — animating discs + status + help affordance (5s
   delayed). 稍后 link removed: drag handle 下滑关闭已覆盖 exit. */
function PairingSearchingBody() {
  const [showFail, setShowFail] = React.useState(false);
  React.useEffect(() => {
    const t = setTimeout(() => setShowFail(true), 5000);
    return () => clearTimeout(t);
  }, []);

  return (
    <div style={{
      flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center',
      padding: '24px 24px 0',
    }}>
      <SensorPair state="searching"/>

      <p style={{ ...T.h1, color: R.ink, marginTop: 36, textAlign: 'center' }}>正在搜索</p>
      <p style={{ ...T.body, color: R.ink3, marginTop: 12, textAlign: 'center' }}>
        两枚都开机，放在手机旁边。
      </p>

      <div style={{ flex: 1 }}/>

      <div style={{
        alignSelf: 'stretch',
        background: R.card, borderRadius: B.cardL, padding: '14px 16px',
        display: 'flex', alignItems: 'center', gap: 12,
        opacity: showFail ? 1 : 0,
        transform: showFail ? 'translateY(0)' : 'translateY(8px)',
        transition: 'opacity .4s ease, transform .4s ease',
        pointerEvents: showFail ? 'auto' : 'none',
        marginBottom: 16,
      }}>
        <div style={{
          width: 32, height: 32, borderRadius: '50%',
          background: R.systemFill,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          flexShrink: 0,
        }}>
          <QuestionGlyph size={14} color={R.ink3}/>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <p style={{ ...T.footnote, color: R.ink, fontWeight: 500 }}>还没找到？</p>
          <p style={{ ...T.footnote, color: R.ink3, marginTop: 2 }}>长按传感器侧面 3 秒重启。</p>
        </div>
      </div>
    </div>
  );
}

/* found body — discs in found state with pop-in animation + L/R info
   rows + 连接 CTA. State label moves to 已发现 (cleaner than "都找到了"). */
function PairingFoundBody({ onConnect }) {
  return (
    <div style={{
      flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center',
      padding: '24px 24px 0',
    }}>
      <div className="pair-found-in">
        <SensorPair state="found"/>
      </div>

      <p style={{ ...T.h1, color: R.ink, marginTop: 36, textAlign: 'center' }}>已发现</p>

      <div style={{ alignSelf: 'stretch', marginTop: 24 }}>
        <InsetGroup>
          <PairRow tone="found" side="L" name="ROOY-3L" rssi="强" battery="84"/>
          <PairRow tone="found" side="R" name="ROOY-3R" rssi="强" battery="82"/>
        </InsetGroup>
      </div>

      <div style={{ flex: 1 }}/>

      <PrimaryCTA onClick={onConnect} style={{ marginBottom: 16 }}>连接</PrimaryCTA>
    </div>
  );
}

/* connected body — discs in connected state + L/R rows + 全部断开 (small
   inline link, less destructive-shouty) + 开始滑行 primary CTA.
   Firmware moved off main view — users don't need it every visit. */
function PairingConnectedBody({ onStart, onDisconnect }) {
  return (
    <div style={{
      flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center',
      padding: '24px 24px 0',
    }}>
      <SensorPair state="connected"/>

      <p style={{ ...T.h1, color: R.ink, marginTop: 36, textAlign: 'center' }}>已连接</p>

      <div style={{ alignSelf: 'stretch', marginTop: 24 }}>
        <InsetGroup>
          <PairRow side="L" name="ROOY-3L" rssi="强" battery="84"/>
          <PairRow side="R" name="ROOY-3R" rssi="强" battery="82"/>
          <FirmwareRow version="1.2.4"/>
        </InsetGroup>
      </div>

      <div style={{ flex: 1 }}/>

      <div style={{ alignSelf: 'stretch', marginBottom: 12, textAlign: 'center' }}>
        <button onClick={onDisconnect} style={{
          background: 'transparent', border: 'none', cursor: 'pointer',
          ...T.footnote, color: R.alert, padding: '8px 16px', minHeight: 36,
        }}>全部断开</button>
      </div>

      <PrimaryCTA onClick={onStart} style={{ marginBottom: 16 }}>开始滑行</PrimaryCTA>
    </div>
  );
}

/* QuestionGlyph — proper ? icon SVG instead of text "?" character.
   Used in the "没找到" help card. */
function QuestionGlyph({ size = 14, color = '#0E1116' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
      <path d="M5.5 6c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5c0 1-0.6 1.6-1.5 2.2-0.6 0.4-1 0.7-1 1.3v0.5"
        stroke={color} strokeWidth="1.6" fill="none" strokeLinecap="round"/>
      <circle cx="8" cy="12.3" r="0.9" fill={color}/>
    </svg>
  );
}

/* FirmwareRow — info row inside the connected InsetGroup. Lighter
   typography than ConnRow (footnote ink3) since firmware isn't
   actionable. */
function FirmwareRow({ version }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', padding: '12px 16px', gap: 14,
    }}>
      <span style={{ ...T.footnote, color: R.ink3, flex: 1 }}>固件</span>
      <span style={{ ...T.footnote, color: R.ink3 }}>
        {version}
      </span>
    </div>
  );
}

/* PairRow — L/R sensor row in the found/connected InsetGroup. `tone`:
   'found' → L/R letter in R.data blue (discovery); default → R.ink
   (already connected). Replaces the old ConnRow/FoundRow pair. */
function PairRow({ side, name, rssi, battery, tone }) {
  const letterColor = tone === 'found' ? R.data : R.ink;
  return (
    <div style={{
      display: 'flex', alignItems: 'center', padding: '14px 16px', gap: 14,
    }}>
      <span style={{
        fontFamily: '"SF Pro Display", system-ui',
        fontSize: 18, fontWeight: 800, color: letterColor,
        letterSpacing: '-0.02em', width: 14, textAlign: 'center',
      }}>{side}</span>
      <span style={{ ...T.body, color: R.ink, flex: 1 }}>{name}</span>
      <span style={{ ...T.footnote, color: R.ink3 }}>
        {rssi} · {battery}%
      </span>
    </div>
  );
}

/* SensorPair — 两枚 disc 并排，左 L 右 R。disc 内字母即左右指示。 */
function SensorPair({ state = 'idle', leftState, rightState, size = 124 }) {
  const lState = leftState || state;
  const rState = rightState || state;
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 28 }}>
      <Sensor state={lState} size={size} label="L"/>
      <Sensor state={rState} size={size} label="R"/>
    </div>
  );
}

/* Sensor — disc + L/R glyph + 状态相关的内部细节。
   核心视觉：扁平实心圆 + 字母 + 状态色。无角标贴纸。
   仅 connected 多一个 R.rooy 绿点（字母正下方，呼吸氛围灯感）。 */
function Sensor({ state = 'idle', size = 124, label = 'L' }) {
  const isIdle = state === 'idle';
  const isSearching = state === 'searching';
  const isFound = state === 'found';
  const isConnected = state === 'connected';

  const ringColor = isIdle ? R.hair2 : R.ink;
  const fillColor = isConnected ? R.ink : 'rgba(14,17,22,0.025)';
  const letterColor = isConnected ? '#fff'
                    : isFound ? R.data
                    : isIdle ? R.ink3
                    : R.ink;

  const letterSize = Math.round(size * 0.42);
  const greenDot = Math.max(5, Math.round(size * 0.055));
  const greenDotBottom = Math.round(size * 0.18);
  const innerRingInset = Math.round(size * 0.09);

  return (
    <div style={{
      width: size, height: size, borderRadius: '50%',
      background: fillColor,
      border: `1.5px solid ${ringColor}`,
      position: 'relative',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      boxShadow: isConnected ? Shadow.lift : 'none',
      overflow: 'hidden',
    }}>
      <div style={{
        position: 'absolute', inset: innerRingInset,
        borderRadius: '50%',
        border: `1px solid ${isConnected ? R.hairD : 'rgba(14,17,22,0.05)'}`,
        pointerEvents: 'none',
      }}/>

      {isSearching && (
        <svg width="100%" height="100%" viewBox="0 0 100 100"
          style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
          {[0, 0.6, 1.2].map((delay, i) => (
            <circle key={i} cx="50" cy="50" r="10" fill="none"
              stroke={R.ink} strokeWidth="1" opacity="0">
              <animate attributeName="r" from="10" to="46"
                dur="1.8s" repeatCount="indefinite" begin={`${delay}s`}/>
              <animate attributeName="opacity"
                values="0;0.55;0" keyTimes="0;0.15;1"
                dur="1.8s" repeatCount="indefinite" begin={`${delay}s`}/>
            </circle>
          ))}
        </svg>
      )}

      <span style={{
        fontFamily: '"SF Pro Display", system-ui',
        fontSize: letterSize, fontWeight: 800,
        color: letterColor, letterSpacing: '-0.02em',
        lineHeight: 1, position: 'relative', zIndex: 1,
      }}>{label}</span>

      {isConnected && (
        <span className="rooy-pair-pulse" style={{
          position: 'absolute', bottom: greenDotBottom, left: '50%',
          transform: 'translateX(-50%)',
          width: greenDot, height: greenDot, borderRadius: '50%',
          background: R.rooy,
          boxShadow: `0 0 ${Math.round(greenDot * 1.6)}px ${R.rooyGlow}`,
        }}/>
      )}
    </div>
  );
}

Object.assign(window, {
  PairingSearching, PairingFound, PairingConnected,
  PairingSheet, PairingSheetScreen,
  Sensor, SensorPair, PairRow, FirmwareRow,
  QuestionGlyph,
});

/* pair-found-in 弹入 keyframe —— 注入一次 */
if (typeof document !== 'undefined' && !document.getElementById('rooy-pair-found-style')) {
  const s = document.createElement('style');
  s.id = 'rooy-pair-found-style';
  s.textContent = `
    @keyframes rooyPairFoundIn {
      0%   { opacity: 0; transform: scale(0.88) translateY(6px); }
      100% { opacity: 1; transform: scale(1) translateY(0); }
    }
    .pair-found-in {
      animation: rooyPairFoundIn .52s cubic-bezier(.22,1.2,.36,1) both;
    }
    /* connected 绿点呼吸 —— 配对成功唯一的彩色时刻 + 动效焦点。
       opacity + scale 双呼吸；transform 保留 translateX(-50%) 居中，
       scale 同时放大 box-shadow 辉光（免费"收张"），无需动 shadow。 */
    @keyframes rooyPairPulse {
      0%, 100% { opacity: .82; transform: translateX(-50%) scale(1); }
      50%      { opacity: 1;   transform: translateX(-50%) scale(1.14); }
    }
    .rooy-pair-pulse {
      animation: rooyPairPulse 2.4s ease-in-out infinite;
    }
    @media (prefers-reduced-motion: reduce) {
      .pair-found-in { animation: none; }
      .rooy-pair-pulse { animation: none; }
    }
  `;
  document.head.appendChild(s);
}
