/* global React */
const { useEffect, useState, useRef } = React;

/**
 * DimmyPill: the floating overlay pill.
 * Props:
 *   state: 'idle' | 'recording' | 'transcribing' | 'processing' | 'done' | 'error'
 *   border: 'rainbow' | 'blue' | 'green' | 'purple' | 'orange' | 'none'
 *   waveform: 'bars' | 'dots' | 'line'
 *   llmDot: hex color (idle indicator)
 *   shortcut: string ('⌃⌥')
 *   timer: string ('00:04')
 *   hover: bool
 */
function DimmyPill({
  state = "idle",
  border = "rainbow",
  waveform = "bars",
  llmDot = "#A78BFA",
  shortcut = "⌃⌥",
  timer = null,
  hover = false,
}) {
  // Animate waveform bars at ~20Hz so they read as a live audio meter
  // rather than a slow ornament. 12Hz felt sleepy.
  const [tick, setTick] = useState(0);
  useEffect(() => {
    if (state !== "recording") return;
    const i = setInterval(() => setTick((t) => t + 1), 50);
    return () => clearInterval(i);
  }, [state]);

  const isRecording = state === "recording";
  const isActive = state !== "idle";

  // Rainbow rotation for the recording border (CSS animation handles this).
  const recordingBorder = border === "rainbow" ? null : pillBorderColor(border);

  const padX =
    state === "idle" ? (hover ? 16 : 14) : isRecording ? 18 : 16;

  // Background opacity: idle 0.5 → 0.95 on hover; recording is thick.
  const bgAlpha = isActive ? 0.85 : hover ? 0.95 : 0.55;
  const blur = isActive ? "blur(40px) saturate(1.5)" : "blur(20px) saturate(1.4)";

  return (
    <div
      style={{
        position: "relative",
        height: 36,
        padding: `0 ${padX}px`,
        display: "inline-flex",
        alignItems: "center",
        gap: 8,
        background: `rgba(16,16,18,${bgAlpha})`,
        backdropFilter: blur,
        WebkitBackdropFilter: blur,
        borderRadius: 9999,
        border: borderRingFor(state, border),
        boxShadow: glowFor(state, border),
        color: "rgba(255,255,255,0.95)",
        fontFamily: "var(--font-sans)",
        fontSize: 12,
        whiteSpace: "nowrap",
        transition: "padding 200ms cubic-bezier(0.4,0,0.2,1), background 200ms",
      }}
    >
      {/* Rainbow rotating ring overlay */}
      {isRecording && border === "rainbow" && <RainbowRing />}
      {isRecording && border !== "rainbow" && border !== "none" && (
        <PulseRing color={recordingBorder} />
      )}

      <PillContent
        state={state}
        waveform={waveform}
        llmDot={llmDot}
        shortcut={shortcut}
        timer={timer}
        hover={hover}
        tick={tick}
      />
    </div>
  );
}

function PillContent({ state, waveform, llmDot, shortcut, timer, hover, tick }) {
  if (state === "idle") {
    // Idle = just the LLM dot. The bars only show up while recording, so
    // there's a clear before/after between "ready" and "listening".
    return (
      <>
        <span
          style={{
            width: 6, height: 6, borderRadius: 999, background: llmDot,
            boxShadow: `0 0 6px ${llmDot}66`,
          }}
        />
        {hover && (
          <span style={{ marginLeft: 8, color: "rgba(255,255,255,0.55)", fontFamily: "var(--font-mono)", fontSize: 11 }}>
            {shortcut}
          </span>
        )}
      </>
    );
  }
  if (state === "recording") {
    return (
      <>
        <Waveform style={waveform} amplitude={1} tick={tick} big />
        {timer && (
          <span style={{ marginLeft: 4, fontFamily: "var(--font-mono)", fontSize: 11, color: "rgba(255,255,255,0.85)" }}>
            {timer}
          </span>
        )}
      </>
    );
  }
  if (state === "transcribing") {
    return (
      <>
        <Spinner color="#38BDF8" />
        <span style={{ color: "#38BDF8" }}>Transcribing…</span>
      </>
    );
  }
  if (state === "processing") {
    return (
      <>
        <Spinner color="#A78BFA" />
        <span style={{ color: "#A78BFA" }}>Processing…</span>
      </>
    );
  }
  if (state === "done") {
    return (
      <>
        <span style={{ color: "#4ADE80", fontWeight: 700 }}>✓</span>
        <span style={{ color: "#4ADE80" }}>Pasted</span>
      </>
    );
  }
  if (state === "error") {
    return (
      <>
        <span style={{ color: "#EF4444", fontWeight: 700 }}>×</span>
        <span style={{ color: "#EF4444" }}>Couldn't transcribe</span>
      </>
    );
  }
  return null;
}

function Waveform({ style = "bars", amplitude = 1, tick = 0, big = false }) {
  // 7 bars, weighted higher in the middle.
  const weights = [0.55, 0.7, 0.85, 1.0, 0.85, 0.7, 0.55];
  // big=true bumps the bar/line height during recording so the waveform
  // reads as "active" and doesn't get visually crowded by the rainbow ring.
  const maxH = big ? 22 : 16;
  const containerH = big ? 24 : 16;
  const barW = big ? 5 : 3;
  const gap = big ? 3 : 2;

  // Per-bar amplitude: combine three rectified sine waves at different
  // frequencies + a small per-bar phase offset, so each bar lives its own
  // life and the cluster reads as a live mic meter, not a synced wave.
  // Returns a multiplier in roughly [0.25, 1.05].
  const meterLevel = (i) => {
    const t = tick * 0.16;
    const a1 = Math.abs(Math.sin(t * 1.7 + i * 1.3));
    const a2 = Math.abs(Math.sin(t * 2.6 + i * 2.7 + 0.4));
    const a3 = Math.abs(Math.sin(t * 0.9 + i * 0.5 + 1.1));
    return 0.25 + a1 * 0.42 + a2 * 0.24 + a3 * 0.18;
  };

  if (style === "dots") {
    return (
      <span style={{ display: "inline-flex", alignItems: "center", gap: 3, height: containerH }}>
        {[0, 1, 2, 3, 4].map((i) => {
          const base = [0.5, 0.75, 1.0, 0.75, 0.5][i];
          const j = meterLevel(i);
          const opacity = Math.min(1, base * amplitude * j);
          const sz = big ? 6 : 5;
          return (
            <i
              key={i}
              style={{
                width: sz, height: sz, borderRadius: 99,
                background: "rgba(255,255,255,0.95)", opacity,
              }}
            />
          );
        })}
      </span>
    );
  }
  if (style === "line") {
    const half = containerH / 2;
    const span = maxH * 0.4;
    const pts = weights.map((w, i) => {
      const j = meterLevel(i);
      const y = half - (w * amplitude * span * j - span * 0.4);
      return `${4 + i * (big ? 11 : 9)},${y.toFixed(1)}`;
    }).join(" ");
    const totalW = 4 + 6 * (big ? 11 : 9) + 4;
    return (
      <svg width={totalW} height={containerH} style={{ display: "block" }}>
        <polyline points={pts} fill="none" stroke="rgba(255,255,255,0.95)"
          strokeWidth={big ? 2.2 : 1.8} strokeLinecap="round" strokeLinejoin="round" />
      </svg>
    );
  }
  // bars — animation lives in CSS (.vu-bar-N classes in index.html), no
  // React tick required. The classes set duration/delay/iteration; we
  // only set the per-bar baseHeight and width here.
  return (
    <span style={{
      display: "inline-flex", alignItems: "flex-end",
      gap, height: containerH,
    }}>
      {weights.map((w, i) => {
        const baseH = Math.max(big ? 8 : 6, w * maxH * amplitude);
        return (
          <span
            key={i}
            className={`vu-bar vu-bar-${i}`}
            style={{
              width: barW,
              height: baseH,
              borderRadius: barW / 2,
              display: "block",
            }}
          />
        );
      })}
    </span>
  );
}

function Spinner({ color }) {
  return (
    <span
      style={{
        width: 12, height: 12, borderRadius: 99,
        border: `1.5px solid ${color}40`, borderTopColor: color,
        animation: "dimmy-spin 700ms linear infinite",
        display: "inline-block",
      }}
    />
  );
}

function RainbowRing() {
  // Static rainbow ring. Rotation made the pill feel like a loading
  // spinner, which competes with the actual recording state. Anchor the
  // gradient at -60deg so the warm colors sit at the top — calmer.
  return (
    <span
      style={{
        position: "absolute", inset: -2, borderRadius: 9999, padding: 2,
        background:
          "conic-gradient(from -60deg, #FF5C5C, #F59E0B, #FBBF24, #4ADE80, #22D3EE, #38BDF8, #A78BFA, #E879F9, #FF5C5C)",
        WebkitMask:
          "linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)",
        WebkitMaskComposite: "xor",
        maskComposite: "exclude",
        pointerEvents: "none",
      }}
    />
  );
}
function PulseRing({ color }) {
  return (
    <span
      style={{
        position: "absolute", inset: -2, borderRadius: 9999,
        border: `2px solid ${color}`, animation: "dimmy-pulse 2.5s ease-in-out infinite",
        pointerEvents: "none",
      }}
    />
  );
}

function pillBorderColor(b) {
  return { blue: "#38BDF8", green: "#4ADE80", purple: "#A78BFA", orange: "#FB923C", none: "#3C3C3C" }[b] || "#3C3C3C";
}
function borderRingFor(state, border) {
  if (state === "idle") return "0.5px solid rgba(255,255,255,0.12)";
  if (state === "transcribing") return "1.5px solid rgba(56,189,248,0.5)";
  if (state === "processing") return "1.5px solid rgba(167,139,250,0.5)";
  if (state === "done") return "1.5px solid rgba(74,222,128,0.5)";
  if (state === "error") return "1.5px solid rgba(239,68,68,0.5)";
  return "2px solid transparent"; // recording, replaced by ring overlay
}
function glowFor(state, border) {
  if (state === "transcribing") return "0 0 12px rgba(56,189,248,0.35), 0 0 8px rgba(56,189,248,0.25)";
  if (state === "processing") return "0 0 12px rgba(167,139,250,0.35), 0 0 8px rgba(167,139,250,0.25)";
  if (state === "done") return "0 0 12px rgba(74,222,128,0.4)";
  if (state === "error") return "0 0 10px rgba(239,68,68,0.45)";
  if (state === "recording") {
    if (border === "rainbow")
      return "0 0 12px rgba(167,139,250,0.40), 0 0 8px rgba(56,189,248,0.40), 0 0 4px rgba(74,222,128,0.40)";
    const c = pillBorderColor(border);
    return `0 0 12px ${c}66, 0 0 8px ${c}33`;
  }
  return "none";
}

window.DimmyPill = DimmyPill;
