// BOLT (Body Oxygen Level Test) — a breath-hold timer and history view.
// Guided: breathe normally → exhale → hold until first air-hunger →
// release. Score = hold duration in seconds.
//
// Bands (McKeown):
//   <10s  poor · 10–20 moderate · 20–30 good · 30–40 very good · 40+ elite

// Labels stay English in data (stable identity for analytics / persisted
// history); display routes through bfBoltBandLabel() using the labelKey.
const BF_BOLT_BANDS = [
  { min: 0,  max: 10, label: 'Starting',  labelKey: 'bolt.band_starting',  h: 15  },
  { min: 10, max: 20, label: 'Moderate',  labelKey: 'bolt.band_moderate',  h: 45  },
  { min: 20, max: 30, label: 'Good',      labelKey: 'bolt.band_good',      h: 155 },
  { min: 30, max: 40, label: 'Very good', labelKey: 'bolt.band_very_good', h: 200 },
  { min: 40, max: 99, label: 'Elite',     labelKey: 'bolt.band_elite',     h: 260 },
];
const bfBoltBand = (s) => BF_BOLT_BANDS.find(b => s >= b.min && s < b.max) || BF_BOLT_BANDS[0];
const bfBoltBandLabel = (b) => {
  if (!b) return '';
  if (b.labelKey && window.BFI18n) return window.BFI18n.t(b.labelKey) || b.label;
  return b.label || '';
};

// Prep phase — structured coaching instead of a vague 30s count.
// Sequence: 5s get ready → 4s inhale → 6s exhale to count → hold starts.
// Voice cues ("inhale" / "exhale") fire at each phase boundary when the
// clips are loaded; silent fallback otherwise. McKeown protocol: hold
// follows a normal (not maximal) exhale.
// Prep phases. Labels/subs are read via BFI18n.t() at render time so they
// stay reactive to language changes — the keys below are the source of
// truth, the English fallbacks match the catalog defaults.
const BF_BOLT_PREP_PHASES = [
  { key: 'ready',  labelKey: 'bolt.get_ready', subKey: 'bolt.ready_sub',  sec: 5, clip: null     },
  { key: 'inhale', labelKey: 'bolt.inhale',    subKey: 'bolt.inhale_sub', sec: 4, clip: 'inhale' },
  { key: 'exhale', labelKey: 'bolt.exhale',    subKey: 'bolt.exhale_sub', sec: 6, clip: 'exhale' },
];
const BF_BOLT_PREP_SECONDS = BF_BOLT_PREP_PHASES.reduce((a, p) => a + p.sec, 0); // 15s total

// Given total elapsed seconds within prep, return the active phase plus
// how many seconds are left inside *this* phase (for the countdown).
function bfBoltPrepAt(elapsed) {
  let t = 0;
  for (const p of BF_BOLT_PREP_PHASES) {
    if (elapsed < t + p.sec) {
      return { phase: p, leftInPhase: (t + p.sec) - elapsed };
    }
    t += p.sec;
  }
  const last = BF_BOLT_PREP_PHASES[BF_BOLT_PREP_PHASES.length - 1];
  return { phase: last, leftInPhase: 0 };
}

function BFBolt({ theme, accentH, voice = true, voicePack = 'en-drew', history = [], onSave }) {
  const [phase, setPhase] = React.useState('intro'); // intro|prep|hold|done
  const [prepElapsed, setPrepElapsed] = React.useState(0);
  const [elapsed, setElapsed] = React.useState(0);
  const [result, setResult] = React.useState(null);
  const startRef = React.useRef(0);
  const spokenRef = React.useRef(null); // last prep sub-phase we fired voice for

  // Normalise pre-i18n pack ids ('drew' → 'en-drew') so old persisted
  // settings keep working without a migration pass.
  const packId = (window.BFVoicePacks && window.BFVoicePacks.migrateLegacyPackId)
    ? window.BFVoicePacks.migrateLegacyPackId(voicePack)
    : (voicePack || 'en-drew');

  // Preload the 'inhale' + 'exhale' cues for the active voice pack so prep
  // cues are zero-latency. Packs without mp3s (or cueUrl() returning null)
  // fall through to TTS via playCue() below. Re-runs when the user switches
  // packs — unloads stale assets first so we never play the wrong locale.
  React.useEffect(() => {
    try {
      if (typeof window === 'undefined' || !window.BFAudio) return;
      window.BFAudio.unload('voice.inhale').catch(() => {});
      window.BFAudio.unload('voice.exhale').catch(() => {});
      if (!voice) return;
      const packs = window.BFVoicePacks;
      if (!packs) return;
      const inhaleUrl = packs.cueUrl(packId, 'inhale');
      const exhaleUrl = packs.cueUrl(packId, 'exhale');
      if (inhaleUrl) window.BFAudio.preload('voice.inhale', inhaleUrl, { volume: 0.9 }).catch(() => {});
      if (exhaleUrl) window.BFAudio.preload('voice.exhale', exhaleUrl, { volume: 0.9 }).catch(() => {});
    } catch (e) {}
  }, [voice, packId]);

  // Play a cue by id. Tries the preloaded mp3 first; on miss (or decode
  // failure), falls back to BFAudio.speak() with the pack's TTS locale so
  // the cue is spoken in the user's selected language even when no clip
  // exists (e.g. freshly added Russian pack with no mp3s generated yet).
  const playCue = React.useCallback((cueId) => {
    if (!voice) return;
    if (typeof window === 'undefined' || !window.BFAudio || !window.BFVoicePacks) return;
    const pack = (window.BF_VOICE_PACKS || {})[packId];
    const locale = pack ? pack.locale : 'en';
    const ttsLang = pack ? pack.ttsLang : null;
    const ttsText = window.BFVoicePacks.cueText(cueId, locale);
    const speak = () => window.BFAudio.speak(ttsText, ttsLang ? { lang: ttsLang } : undefined).catch(() => {});
    const assetId = 'voice.' + cueId;
    if (window.BFAudio.isLoaded(assetId)) {
      window.BFAudio.play(assetId, { restart: true }).catch(speak);
    } else {
      speak();
    }
  }, [voice, packId]);

  React.useEffect(() => {
    if (phase !== 'prep') return;
    setPrepElapsed(0);
    spokenRef.current = null;
    const startedAt = performance.now();
    const id = setInterval(() => {
      const e = (performance.now() - startedAt) / 1000;
      setPrepElapsed(e);
      if (e >= BF_BOLT_PREP_SECONDS) { clearInterval(id); setPhase('hold'); }
    }, 100);
    return () => clearInterval(id);
  }, [phase]);

  // Fire a voice cue once per prep sub-phase boundary. Routes through
  // playCue() so the pack manifest decides mp3-vs-TTS and the right locale.
  React.useEffect(() => {
    if (phase !== 'prep') return;
    if (!voice) return;
    const { phase: sub } = bfBoltPrepAt(prepElapsed);
    if (spokenRef.current === sub.key) return;
    spokenRef.current = sub.key;
    if (!sub.clip) return;
    playCue(sub.clip);
  }, [phase, prepElapsed, voice, playCue]);

  React.useEffect(() => {
    if (phase !== 'hold') return;
    startRef.current = performance.now();
    const id = setInterval(() => setElapsed((performance.now() - startRef.current) / 1000), 100);
    return () => clearInterval(id);
  }, [phase]);

  const stop = () => { setResult(Math.round(elapsed)); setPhase('done'); };
  const { phase: prepStep, leftInPhase } = bfBoltPrepAt(prepElapsed);
  const prepLeft = Math.max(0, BF_BOLT_PREP_SECONDS - prepElapsed);

  const last = history[history.length - 1];
  const best = history.reduce((m, h) => Math.max(m, h.score), 0);

  // Locale shortcut. Resolved on every render so language switches apply
  // immediately (parent re-renders this whole tree on uiLocale change).
  const t = (k, p) => (window.BFI18n ? window.BFI18n.t(k, p) : k);
  const prepLabel = t(prepStep.labelKey);
  const prepSub   = t(prepStep.subKey);

  return (
    <div style={{ padding: '64px 20px calc(110px + env(safe-area-inset-bottom, 0px))', color: theme.fg, fontFamily: BF_FONTS.sans }}>
      <div style={{ fontSize: 13, color: theme.fgFaint }}>{t('bolt.subtitle')}</div>
      <div style={{ fontFamily: BF_FONTS.serif, fontSize: 34, fontStyle: 'italic', marginTop: 4, letterSpacing: -0.4 }}>{t('bolt.title')}</div>

      {phase === 'intro' && (
        <>
          <div style={{ fontSize: 14, color: theme.fgMuted, marginTop: 14, textWrap: 'pretty', lineHeight: 1.5 }}>
            {t('bolt.intro')}
          </div>

          {/* Primary CTA — lifted to the top so the Begin button is always
              visible without scrolling. The lower duplicate was removed. */}
          <button onClick={() => setPhase('prep')} style={{
            width: '100%', height: 56, borderRadius: 999, border: 'none', cursor: 'pointer',
            background: bfAccentSolid(accentH), color: bfAccentSolidFg(),
            fontFamily: BF_FONTS.sans, fontSize: 15, fontWeight: 600,
            marginTop: 18, marginBottom: 4,
            boxShadow: `0 8px 24px oklch(0.78 0.1 ${accentH} / 0.3)`,
          }}>{t('bolt.begin')}</button>
          <div style={{ fontSize: 11, color: theme.fgFaint, textAlign: 'center', marginBottom: 18 }}>
            {t('bolt.prep_hint')}
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 16 }}>
            <BFCard theme={theme} style={{ padding: 14, textAlign: 'center' }}>
              <div style={{ fontFamily: BF_FONTS.serif, fontSize: 30, fontStyle: 'italic' }}>{last ? last.score : '—'}</div>
              <div style={{ fontSize: 10, letterSpacing: 0.5, textTransform: 'uppercase', color: theme.fgFaint, marginTop: 4 }}>{t('bolt.last')}</div>
            </BFCard>
            <BFCard theme={theme} style={{ padding: 14, textAlign: 'center' }}>
              <div style={{ fontFamily: BF_FONTS.serif, fontSize: 30, fontStyle: 'italic' }}>{best || '—'}</div>
              <div style={{ fontSize: 10, letterSpacing: 0.5, textTransform: 'uppercase', color: theme.fgFaint, marginTop: 4 }}>{t('bolt.best')}</div>
            </BFCard>
          </div>

          {/* History chart */}
          {history.length > 1 && (
            <BFCard theme={theme} style={{ padding: 16, marginBottom: 18 }}>
              <div style={{ fontSize: 12, color: theme.fgMuted, marginBottom: 10 }}>{t('bolt.trend')}</div>
              <BoltChart data={history} accentH={accentH} theme={theme} />
            </BFCard>
          )}

          {/* Bands */}
          <div style={{ fontSize: 11, letterSpacing: 1, textTransform: 'uppercase', color: theme.fgFaint, marginBottom: 8 }}>{t('bolt.bands')}</div>
          <BFCard theme={theme} style={{ padding: 0, overflow: 'hidden', marginBottom: 22 }}>
            {BF_BOLT_BANDS.map((b, i) => (
              <div key={b.label} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 14px', borderBottom: i < BF_BOLT_BANDS.length - 1 ? `1px solid ${theme.line}` : 'none' }}>
                <div style={{ width: 10, height: 10, borderRadius: 999, background: bfAccentSolid(b.h) }} />
                <div style={{ flex: 1, fontSize: 13 }}>{bfBoltBandLabel(b)}</div>
                <div style={{ fontFamily: BF_FONTS.mono, fontSize: 12, color: theme.fgFaint }}>{b.min}–{b.max === 99 ? '40+' : b.max}s</div>
              </div>
            ))}
          </BFCard>
        </>
      )}

      {phase === 'prep' && (
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: 40, gap: 24 }}>
          {/* Amplitude mirrors the active phase — grows on inhale, shrinks on exhale.
              Ready phase is a soft idle at 0.45. */}
          <BreathingVisualizer
            style="circle"
            amplitude={prepStep.key === 'inhale' ? 0.85 : prepStep.key === 'exhale' ? 0.25 : 0.45}
            accentH={accentH}
            size={220}
            theme={theme}
          />
          <div style={{ textAlign: 'center' }}>
            <div style={{ fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', color: theme.fgFaint }}>{t('bolt.prepare')}</div>
            <div style={{ fontFamily: BF_FONTS.serif, fontSize: 34, fontStyle: 'italic', marginTop: 8, color: theme.fg }}>{prepLabel}</div>
            <div style={{ fontSize: 13, color: theme.fgMuted, marginTop: 6, maxWidth: 280 }}>{prepSub}</div>
          </div>
          {/* Per-phase countdown — clearer signal than the global "30s" blob. */}
          <div style={{ fontFamily: BF_FONTS.mono, fontSize: 56, color: theme.fg, letterSpacing: -2, lineHeight: 1 }}>
            {Math.ceil(leftInPhase)}
            <span style={{ fontSize: 22, color: theme.fgFaint, marginLeft: 2 }}>s</span>
          </div>
          {/* Overall prep progress bar — thin, accent-tinted. */}
          <div style={{ width: '70%', maxWidth: 240, height: 3, background: theme.line, borderRadius: 999, overflow: 'hidden' }}>
            <div style={{
              width: `${Math.min(100, (prepElapsed / BF_BOLT_PREP_SECONDS) * 100)}%`,
              height: '100%',
              background: bfAccentSolid(accentH),
              transition: 'width 0.1s linear',
            }} />
          </div>
          <div style={{ display: 'flex', gap: 10 }}>
            <button onClick={() => setPhase('hold')} style={{
              padding: '12px 22px', borderRadius: 999, border: `1px solid ${theme.line}`, cursor: 'pointer',
              background: theme.cardSoft, color: theme.fg,
              fontSize: 13, fontWeight: 500,
            }}>{t('bolt.skip_to_hold')}</button>
            <button onClick={() => { setPhase('intro'); setPrepElapsed(0); }} style={{
              padding: '12px 22px', borderRadius: 999, border: `1px solid ${theme.line}`, cursor: 'pointer',
              background: theme.cardSoft, color: theme.fgMuted,
              fontSize: 13, fontWeight: 500,
            }}>{t('bolt.cancel')}</button>
          </div>
        </div>
      )}

      {phase === 'hold' && (
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: 50, gap: 32 }}>
          <BreathingVisualizer style="circle" amplitude={0.55} accentH={accentH} size={220} theme={theme} />
          <div style={{ textAlign: 'center' }}>
            <div style={{ fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', color: theme.fgFaint }}>{t('bolt.hold')}</div>
            <div style={{ fontFamily: BF_FONTS.mono, fontSize: 56, marginTop: 4, letterSpacing: -2, color: theme.fg }}>
              {Math.floor(elapsed)}<span style={{ fontSize: 28, color: theme.fgFaint }}>s</span>
            </div>
          </div>
          <button onClick={stop} style={{
            padding: '14px 44px', borderRadius: 999, border: 'none', cursor: 'pointer',
            background: bfAccentSolid(accentH), color: bfAccentSolidFg(),
            fontSize: 14, fontWeight: 600,
          }}>{t('bolt.need_breath')}</button>
        </div>
      )}

      {phase === 'done' && (() => {
        const band = bfBoltBand(result);
        return (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: 40, gap: 20, textAlign: 'center' }}>
            <div style={{ fontFamily: BF_FONTS.serif, fontSize: 80, fontStyle: 'italic', color: bfAccentText(theme, band.h), lineHeight: 1 }}>{result}</div>
            <div style={{ fontSize: 12, letterSpacing: 2, textTransform: 'uppercase', color: theme.fgFaint }}>{t('bolt.seconds', { band: bfBoltBandLabel(band) })}</div>
            <div style={{ fontSize: 14, color: theme.fgMuted, maxWidth: 280, textWrap: 'pretty', marginTop: 6 }}>
              {t('bolt.retest_hint')}
            </div>
            <button onClick={() => { onSave?.(result); setPhase('intro'); setElapsed(0); setResult(null); setPrepElapsed(0); }} style={{
              marginTop: 16, padding: '14px 36px', borderRadius: 999, border: 'none', cursor: 'pointer',
              background: bfAccentSolid(accentH), color: bfAccentSolidFg(),
              fontSize: 14, fontWeight: 600,
            }}>{t('bolt.save')}</button>
          </div>
        );
      })()}
    </div>
  );
}

function BoltChart({ data, accentH, theme }) {
  const W = 320, H = 110, pad = 8;
  const max = Math.max(40, ...data.map(d => d.score));
  const step = (W - pad * 2) / Math.max(1, data.length - 1);
  const pts = data.map((d, i) => [pad + i * step, H - pad - (d.score / max) * (H - pad * 2)]);
  const path = pts.map((p, i) => (i === 0 ? 'M' : 'L') + p.join(',')).join(' ');
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: 'block' }}>
      <path d={path} fill="none" stroke={bfAccentText(theme, accentH)} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
      {pts.map((p, i) => <circle key={i} cx={p[0]} cy={p[1]} r="3" fill={theme.bg} stroke={bfAccentText(theme, accentH)} strokeWidth="1.5" />)}
    </svg>
  );
}

// ── Rewards screen ─────────────────────────────────────────────────
function BFRewards({ theme, accentH, session }) {
  const tiers = [
    { name: 'Bronze',   req: 3,   unlocked: session.streak >= 3,   desc: '3-day streak' },
    { name: 'Silver',   req: 7,   unlocked: session.streak >= 7,   desc: 'One week' },
    { name: 'Gold',     req: 21,  unlocked: session.streak >= 21,  desc: 'Three weeks · habit formed' },
    { name: 'Platinum', req: 60,  unlocked: session.streak >= 60,  desc: 'Two months' },
    { name: 'Diamond',  req: 180, unlocked: session.streak >= 180, desc: 'Six months' },
  ];
  const badges = [
    { name: 'Dawn practitioner', done: true,  desc: 'Session before 7am' },
    { name: 'Night owl',         done: false, desc: 'Session after 10pm' },
    { name: 'All four patterns', done: false, desc: 'Try every flow' },
    { name: 'BOLT 20',           done: true,  desc: 'Reach 20s breath hold' },
    { name: 'Century',           done: false, desc: '100 total sessions' },
    { name: 'Consistency',       done: true,  desc: '7 days in a row' },
  ];
  return (
    <div style={{ padding: '64px 20px calc(110px + env(safe-area-inset-bottom, 0px))', color: theme.fg, fontFamily: BF_FONTS.sans }}>
      <div style={{ fontSize: 13, color: theme.fgFaint }}>Rewards</div>
      <div style={{ fontFamily: BF_FONTS.serif, fontSize: 34, fontStyle: 'italic', marginTop: 4, letterSpacing: -0.4 }}>Your growth</div>

      {/* Tier ladder */}
      <div style={{ marginTop: 22, marginBottom: 22 }}>
        <div style={{ fontSize: 11, letterSpacing: 1, textTransform: 'uppercase', color: theme.fgFaint, marginBottom: 10 }}>Streak tiers</div>
        <BFCard theme={theme} style={{ padding: 18 }}>
          {tiers.map((t, i) => {
            const active = t.unlocked;
            return (
              <div key={t.name} style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '10px 0', borderBottom: i < tiers.length - 1 ? `1px solid ${theme.line}` : 'none' }}>
                <div style={{
                  width: 40, height: 40, borderRadius: 999, flexShrink: 0,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  background: active ? bfAccentTint(theme, accentH, 0.2) : theme.cardSoft,
                  color: active ? bfAccentText(theme, accentH) : theme.fgFaint,
                }}>
                  <BFIcon name={active ? 'trophy' : 'lock'} size={18} />
                </div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 14, fontWeight: 500, color: active ? theme.fg : theme.fgMuted }}>{t.name}</div>
                  <div style={{ fontSize: 12, color: theme.fgFaint, marginTop: 2 }}>{t.desc}</div>
                </div>
                <div style={{ fontFamily: BF_FONTS.mono, fontSize: 12, color: theme.fgFaint }}>{t.req}d</div>
              </div>
            );
          })}
        </BFCard>
      </div>

      {/* Badges */}
      <div style={{ fontSize: 11, letterSpacing: 1, textTransform: 'uppercase', color: theme.fgFaint, marginBottom: 10 }}>Badges</div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
        {badges.map((b, i) => (
          <BFCard key={i} theme={theme} style={{ padding: 12, opacity: b.done ? 1 : 0.45 }}>
            <div style={{
              width: 36, height: 36, borderRadius: 10, marginBottom: 8,
              background: b.done ? bfAccentTint(theme, accentH, 0.2) : theme.cardSoft,
              color: b.done ? bfAccentText(theme, accentH) : theme.fgFaint,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <BFIcon name={b.done ? 'sparkle' : 'lock'} size={16} />
            </div>
            <div style={{ fontSize: 13, fontWeight: 500, lineHeight: 1.2 }}>{b.name}</div>
            <div style={{ fontSize: 11, color: theme.fgFaint, marginTop: 3 }}>{b.desc}</div>
          </BFCard>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, { BFBolt, BFRewards, BF_BOLT_BANDS, bfBoltBand, bfBoltBandLabel });
