// Three BreathingVisualizer variants — each a pure function of
// { amplitude, phase, accentH, size }. Amplitude (0..1) drives "fullness",
// phase is the string label. Shared contract so they're drop-in swappable.

// ── Circle ───────────────────────────────────────────────────────────
// Classic glowing orb. Two layered rings (gas + core) + a soft halo.
// The halo fades on exhale; the core gets a subtle inner shadow on hold.
function VizCircle({ amplitude = 0, phase = 'inhale', accentH = 200, size = 280, dark = true }) {
  const min = 0.42, max = 1.0;
  const s = min + amplitude * (max - min);
  const haloAlpha = 0.18 + amplitude * 0.32;
  const ringAlpha = dark ? 0.85 : 0.7;
  const coreColor = `oklch(0.78 0.08 ${accentH})`;
  const glowColor = `oklch(0.78 0.1 ${accentH})`;
  return (
    <svg viewBox="-150 -150 300 300" width={size} height={size} style={{ display: 'block' }}>
      <defs>
        <radialGradient id={`bf-halo-${accentH}`} cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor={glowColor} stopOpacity={haloAlpha} />
          <stop offset="55%" stopColor={glowColor} stopOpacity={haloAlpha * 0.3} />
          <stop offset="100%" stopColor={glowColor} stopOpacity="0" />
        </radialGradient>
        <radialGradient id={`bf-core-${accentH}`} cx="35%" cy="30%" r="85%">
          <stop offset="0%"   stopColor={`oklch(0.92 0.04 ${accentH})`} stopOpacity="0.95" />
          <stop offset="55%"  stopColor={coreColor} stopOpacity={ringAlpha} />
          <stop offset="100%" stopColor={`oklch(0.58 0.09 ${accentH})`} stopOpacity={ringAlpha} />
        </radialGradient>
      </defs>
      {/* halo */}
      <circle r={135} fill={`url(#bf-halo-${accentH})`} style={{ transition: 'r 60ms linear' }} />
      {/* guide ring */}
      <circle r={120} fill="none" stroke={dark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)'} strokeWidth="1" strokeDasharray="2 4" />
      {/* breathing core */}
      <circle r={100 * s} fill={`url(#bf-core-${accentH})`} />
      {/* inner highlight */}
      <circle r={100 * s} fill="none" stroke={`oklch(0.98 0.02 ${accentH} / 0.5)`} strokeWidth="0.8" />
    </svg>
  );
}

// ── Geometric (square + orbiting dot) ───────────────────────────────
// A true square that breathes in size with amplitude, and a pacer dot
// that traces its perimeter — one full lap per breathing cycle. The
// phase determines which edge the dot is on, so a user can match the
// dot to their breath. Intended for "focus" patterns.
function VizGeometric({ amplitude = 0, phase = 'inhale', phaseT = 0, accentH = 200, size = 280, dark = true }) {
  const min = 0.55, max = 1.0;
  const s = min + amplitude * (max - min);
  const half = 100 * s;
  const stroke = `oklch(0.78 0.08 ${accentH})`;
  const strokeFaint = `oklch(0.78 0.08 ${accentH} / 0.2)`;
  const fill = `oklch(0.78 0.08 ${accentH} / ${0.06 + amplitude * 0.1})`;

  // Dot walks the square perimeter. Map phase → which edge:
  //   inhale  → top edge  (left→right)
  //   holdIn  → right edge (top→bottom)
  //   exhale  → bottom edge (right→left)
  //   holdOut → left edge  (bottom→top)
  const edges = {
    inhale:  (t) => [-half + 2 * half * t, -half],
    holdIn:  (t) => [ half, -half + 2 * half * t],
    exhale:  (t) => [ half - 2 * half * t,  half],
    holdOut: (t) => [-half,  half - 2 * half * t],
  };
  const pos = (edges[phase] || edges.inhale)(Math.min(1, Math.max(0, phaseT)));

  return (
    <svg viewBox="-150 -150 300 300" width={size} height={size} style={{ display: 'block' }}>
      {/* outer guide square */}
      <rect x={-120} y={-120} width={240} height={240} rx={6} fill="none" stroke={strokeFaint} strokeWidth="0.8" strokeDasharray="2 5" />
      {/* breathing square */}
      <rect x={-half} y={-half} width={half * 2} height={half * 2} rx={4}
            fill={fill} stroke={stroke} strokeWidth="1.6" />
      {/* inner ghost square */}
      <rect x={-half * 0.55} y={-half * 0.55} width={half * 1.1} height={half * 1.1} rx={3}
            fill="none" stroke={strokeFaint} strokeWidth="0.8" />
      {/* center dot */}
      <circle r={3} fill={stroke} opacity="0.35" />
      {/* pacer dot + its glow */}
      <circle cx={pos[0]} cy={pos[1]} r={14} fill={`oklch(0.78 0.1 ${accentH} / 0.25)`} />
      <circle cx={pos[0]} cy={pos[1]} r={7}  fill={`oklch(0.88 0.08 ${accentH})`} />
    </svg>
  );
}

// ── Flower ───────────────────────────────────────────────────────────
// Six-petaled bloom. Each petal's length tracks amplitude; petals fan
// slightly on inhale and close on exhale. Soft, organic — default for
// "calm" patterns.
function VizFlower({ amplitude = 0, phase = 'inhale', accentH = 200, size = 280, dark = true }) {
  const a = amplitude;
  const petalL = 42 + a * 68;     // length grows with amplitude
  const petalW = 22 + a * 14;
  const fan = 0 + a * 6;           // extra angular spread
  const petalFill = `oklch(0.78 0.08 ${accentH} / ${0.22 + a * 0.22})`;
  const petalStroke = `oklch(0.82 0.08 ${accentH} / 0.45)`;
  const core = `oklch(0.88 0.06 ${accentH})`;
  const petals = [];
  const N = 6;
  for (let i = 0; i < N; i++) {
    const ang = (360 / N) * i + (i % 2 === 0 ? fan : -fan);
    petals.push(
      <g key={i} transform={`rotate(${ang})`}>
        <ellipse cx="0" cy={-petalL * 0.55} rx={petalW} ry={petalL} fill={petalFill} stroke={petalStroke} strokeWidth="0.8" />
      </g>
    );
  }
  return (
    <svg viewBox="-150 -150 300 300" width={size} height={size} style={{ display: 'block' }}>
      <defs>
        <radialGradient id={`bf-flower-core-${accentH}`} cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor={core} stopOpacity="0.9" />
          <stop offset="100%" stopColor={core} stopOpacity="0" />
        </radialGradient>
      </defs>
      {/* faint ring */}
      <circle r={130} fill="none" stroke={dark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)'} strokeWidth="1" strokeDasharray="1 5" />
      {/* second layer, rotated */}
      <g transform={`rotate(${30 - a * 12}) scale(${0.7 + a * 0.2})`} opacity={0.55}>
        {petals}
      </g>
      {/* primary layer */}
      <g>{petals}</g>
      {/* glowing core */}
      <circle r={30 + a * 14} fill={`url(#bf-flower-core-${accentH})`} />
      <circle r={6 + a * 2} fill={core} />
    </svg>
  );
}

// ── Balloon (Kids mode) ─────────────────────────────────────────────
// Playful balloon that inflates on inhale and deflates on exhale. The knot
// + string hang below and sway slightly with amplitude. Uses the active
// accent hue for the balloon body with a brighter highlight on one shoulder
// and a faint halo for warmth. Default visualizer when the active profile
// is kind='kid'.
//
// Amplitude drives scale 0.55 → 1.05 (bigger max than other viz so the
// balloon really feels like it fills on a deep inhale). The pear/teardrop
// silhouette comes from a cubic path; it scales uniformly from the knot
// as the anchor so the balloon visually "floats up" as it inflates.
function VizBalloon({ amplitude = 0, phase = 'inhale', phaseT = 0, accentH = 200, size = 280, dark = true }) {
  const a = Math.max(0, Math.min(1, amplitude));
  const s = 0.55 + a * 0.5;  // 0.55 .. 1.05
  // Slight bob during holds so a static balloon doesn't look frozen.
  const bob = (phase === 'holdIn' || phase === 'holdOut')
    ? Math.sin(phaseT * Math.PI * 2) * 3
    : 0;
  const sway = Math.sin((phaseT || 0) * Math.PI) * 2 * (phase === 'holdOut' ? 1 : 0.5);

  const body       = `oklch(0.78 0.12 ${accentH})`;
  const bodyDeep   = `oklch(0.62 0.12 ${accentH})`;
  const highlight  = `oklch(0.96 0.04 ${accentH})`;
  const halo       = `oklch(0.85 0.12 ${accentH})`;
  const stringCol  = dark ? 'rgba(255,255,255,0.55)' : 'rgba(0,0,0,0.55)';

  // Anchor: the knot is fixed near y=60 in unscaled coords, so as the body
  // scales, the bottom stays put and the top grows upward — feels like the
  // balloon is filling, not just zooming.
  // Balloon body path: a rounded teardrop. Centered at (0,0) with knot at
  // bottom; scaling happens around (0, 60).
  return (
    <svg viewBox="-150 -170 300 340" width={size} height={size} style={{ display: 'block' }}>
      <defs>
        <radialGradient id={`bf-balloon-body-${accentH}`} cx="32%" cy="30%" r="75%">
          <stop offset="0%"   stopColor={highlight} stopOpacity="0.95" />
          <stop offset="40%"  stopColor={body}      stopOpacity="0.95" />
          <stop offset="100%" stopColor={bodyDeep}  stopOpacity="0.95" />
        </radialGradient>
        <radialGradient id={`bf-balloon-halo-${accentH}`} cx="50%" cy="50%" r="55%">
          <stop offset="0%"   stopColor={halo} stopOpacity={0.12 + a * 0.18} />
          <stop offset="100%" stopColor={halo} stopOpacity="0" />
        </radialGradient>
      </defs>

      {/* soft halo */}
      <circle cx="0" cy={-20 + bob} r={130} fill={`url(#bf-balloon-halo-${accentH})`} />

      {/* guide dots — faint, keeps the frame anchored */}
      <circle r={1.2} cx={-130} cy={120} fill={dark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)'} />
      <circle r={1.2} cx={ 130} cy={120} fill={dark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)'} />

      {/* string (swings slightly with phase) */}
      <path
        d={`M 0 60 Q ${sway} 100 ${sway * 0.6} 150`}
        fill="none"
        stroke={stringCol}
        strokeWidth="1.2"
        strokeLinecap="round"
      />

      {/* balloon body + knot, scaled around (0, 60) */}
      <g transform={`translate(0 ${bob}) scale(${s}) translate(0 ${(1 - 1 / s) * 60})`}>
        {/* body */}
        <path
          d="M 0 -110
             C  70 -110  90  -60  90  -10
             C  90   60  40   70   0   70
             C -40   70 -90   60 -90  -10
             C -90  -60 -70 -110   0 -110 Z"
          fill={`url(#bf-balloon-body-${accentH})`}
          stroke={bodyDeep}
          strokeOpacity="0.4"
          strokeWidth="1.4"
        />
        {/* knot — small triangle at the base */}
        <path
          d="M -8 68 L 8 68 L 0 82 Z"
          fill={bodyDeep}
          opacity="0.85"
        />
        {/* shine — curved highlight on upper-left shoulder */}
        <path
          d="M -50 -80 Q -70 -40 -55 -10"
          fill="none"
          stroke={highlight}
          strokeOpacity="0.75"
          strokeWidth="4"
          strokeLinecap="round"
        />
        {/* tiny dot highlight */}
        <circle cx={-30} cy={-70} r={5} fill={highlight} opacity="0.9" />
      </g>
    </svg>
  );
}

// ── Dragon (kids: Dragon Breath) ───────────────────────────────────────
// Dragon-HEAD silhouette in profile (not the full body — too small to read
// the whole shape). Yellow/orange flames stream from the mouth and react
// to the breath phase:
//   - Exhale  → flames emerge at the mouth and drift outward, growing
//   - Inhale  → flames appear far from the mouth and travel back IN,
//               shrinking as they approach (air being drawn into the
//               dragon — visual reverse of the exhale).
//   - HoldIn  → no flames (held breath inside the dragon)
//   - HoldOut → small fading puff at the far edge
// Body picks up the user's accent so themes still apply, but the flames
// stay warm yellow/orange (oklch hue ~70°) so they read as fire across
// every accent + dark/light combo.
function VizDragon({ amplitude = 0, phase = 'inhale', phaseT = 0, accentH = 200, size = 280, dark = true }) {
  const a = Math.max(0, Math.min(1, amplitude));
  // Head bobs gently during holds so a static silhouette doesn't look frozen.
  const bob = (phase === 'holdIn' || phase === 'holdOut')
    ? Math.sin(phaseT * Math.PI * 2) * 2
    : 0;

  const body       = `oklch(0.78 0.12 ${accentH})`;
  const bodyDeep   = `oklch(0.55 0.12 ${accentH})`;
  const highlight  = `oklch(0.96 0.04 ${accentH})`;
  const dark2      = dark ? 'oklch(0.18 0.01 245)' : 'oklch(0.25 0.02 245)';
  const flameYel   = 'oklch(0.92 0.18 95)';   // bright yellow core
  const flameOrng  = 'oklch(0.72 0.22 55)';   // orange falloff

  // breathT drives the flame trail position 0→1 (mouth→far) and size 0→1.
  //   exhale  : 0→1 (puffing OUT, growing)
  //   inhale  : 1→0 (drawn IN from far, shrinking) — same path, reversed
  //   holdIn  : 0   (held inside, hidden)
  //   holdOut : 1   (lingering at far edge, fading)
  let breathT = 0;
  let flameAlpha = 0;
  if (phase === 'exhale')  { breathT = phaseT;     flameAlpha = 1; }
  else if (phase === 'inhale')   { breathT = 1 - phaseT; flameAlpha = 1; }
  else if (phase === 'holdOut')  { breathT = 1;          flameAlpha = Math.max(0, 1 - phaseT); }
  else                            { breathT = 0;          flameAlpha = 0; }

  // Three flame puffs trail behind one another. flameOffset shifts each one
  // back along the breath axis so they form a stream, not a single blob.
  const renderFlame = (flameOffset, baseSize) => {
    const t = Math.max(0, Math.min(1, breathT - flameOffset));
    const opacity = flameAlpha * (1 - t * 0.4);
    if (opacity <= 0.02) return null;
    // Mouth at x=58, far edge at x=132. Flame y aligns with mouth (y=14).
    const x = 58 + t * 74;
    // Size grows with t — small at mouth, big at far edge.
    const r = baseSize * (0.4 + t * 0.9);
    return (
      <g opacity={opacity}>
        <circle cx={x} cy={14 + bob} r={r * 1.6} fill="url(#bf-dragon-fire-outer)" />
        <circle cx={x} cy={14 + bob} r={r}       fill="url(#bf-dragon-fire-inner)" />
      </g>
    );
  };

  return (
    <svg viewBox="-150 -150 300 300" width={size} height={size} style={{ display: 'block' }}>
      <defs>
        <radialGradient id={`bf-dragon-body-${accentH}`} cx="35%" cy="40%" r="80%">
          <stop offset="0%"   stopColor={highlight} stopOpacity="0.95" />
          <stop offset="55%"  stopColor={body}      stopOpacity="0.95" />
          <stop offset="100%" stopColor={bodyDeep}  stopOpacity="0.95" />
        </radialGradient>
        <radialGradient id="bf-dragon-fire-outer" cx="50%" cy="50%" r="55%">
          <stop offset="0%"   stopColor={flameOrng} stopOpacity="0.75" />
          <stop offset="100%" stopColor={flameOrng} stopOpacity="0" />
        </radialGradient>
        <radialGradient id="bf-dragon-fire-inner" cx="50%" cy="50%" r="55%">
          <stop offset="0%"   stopColor={flameYel}  stopOpacity="1" />
          <stop offset="60%"  stopColor={flameOrng} stopOpacity="0.85" />
          <stop offset="100%" stopColor={flameOrng} stopOpacity="0" />
        </radialGradient>
      </defs>

      {/* Soft halo, breathes with amplitude */}
      <circle cx="-10" cy={bob} r={110 * (0.85 + a * 0.18)}
              fill={`url(#bf-dragon-body-${accentH})`} opacity="0.07" />

      {/* Dragon HEAD in profile, facing right. Built from a single path:
          back of skull → horns → snout → jaw → throat. Centered on origin. */}
      <g transform={`translate(0 ${bob})`}>
        {/* Two horns curving back */}
        <path
          d="M -38 -52 Q -52 -72 -64 -64 Q -56 -56 -42 -42 Z"
          fill={bodyDeep} opacity="0.85"
        />
        <path
          d="M -22 -56 Q -32 -78 -48 -76 Q -36 -64 -24 -46 Z"
          fill={bodyDeep} opacity="0.85"
        />

        {/* Main head silhouette — back of skull on the left, snout pointing
            right, lower jaw with a small opening near the mouth. */}
        <path
          d="M -78 -10
             Q -90 -42  -54 -50
             Q -10 -58   38 -32
             Q  60 -22   62  -2
             L  58  10
             Q  44  18   28  16
             L  18  20
             Q  10  30  -4  32
             Q -28  36 -54  26
             Q -76  18 -82  0
             Q -86 -8 -78 -10 Z"
          fill={`url(#bf-dragon-body-${accentH})`}
          stroke={bodyDeep}
          strokeOpacity="0.5"
          strokeWidth="1.4"
        />

        {/* Lower jaw line / mouth opening — small gap so flames look like
            they emerge from a real mouth, not the cheek. */}
        <path
          d="M 28 16 Q 38 12 56 6"
          stroke={bodyDeep} strokeOpacity="0.6" strokeWidth="1.6" fill="none" strokeLinecap="round"
        />

        {/* Tooth (just one, kid-friendly) */}
        <path
          d="M 38 14 L 41 22 L 44 14 Z"
          fill={highlight} opacity="0.85"
        />

        {/* Nostril */}
        <circle cx="48" cy="-6" r="2" fill={dark2} opacity="0.7" />

        {/* Eye — the focal point, kept simple */}
        <circle cx="-12" cy="-28" r="6" fill={highlight} />
        <circle cx="-10" cy="-26" r="3.5" fill={dark2} />

        {/* Brow ridge to make the eye read as alert, not sleepy */}
        <path
          d="M -22 -36 Q -10 -42 4 -36"
          stroke={bodyDeep} strokeOpacity="0.7" strokeWidth="2" fill="none" strokeLinecap="round"
        />

        {/* Soft shoulder highlight */}
        <path
          d="M -56 -28 Q -34 -42 -10 -38"
          stroke={highlight} strokeOpacity="0.6" strokeWidth="3" fill="none" strokeLinecap="round"
        />
      </g>

      {/* Flame stream from the mouth. Three puffs offset along the breath
          axis so they form a trail; each fades + grows independently. */}
      {renderFlame(0.0, 9)}
      {renderFlame(0.18, 7)}
      {renderFlame(0.36, 5)}
    </svg>
  );
}

// Dispatcher — one component to drive them by name. Derives the `dark` prop
// from the theme object if a caller didn't pass one explicitly. Keeps
// existing call sites that pass `dark` directly working unchanged, while
// letting most call sites just pass `theme` and have light/dark sort itself.
function BreathingVisualizer({ style = 'circle', dark, theme, ...rest }) {
  const resolvedDark = (typeof dark === 'boolean')
    ? dark
    : (typeof window.bfIsLightTheme === 'function' ? !window.bfIsLightTheme(theme) : true);
  const props = { ...rest, dark: resolvedDark };
  if (style === 'geometric') return <VizGeometric {...props} />;
  if (style === 'flower')    return <VizFlower {...props} />;
  if (style === 'balloon')   return <VizBalloon {...props} />;
  if (style === 'dragon')    return <VizDragon {...props} />;
  return <VizCircle {...props} />;
}

Object.assign(window, { BreathingVisualizer, VizCircle, VizGeometric, VizFlower, VizBalloon, VizDragon });
