/* Shared small components: header, toggles, gauge, pill, etc. */

const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ───────── Toggle pill (On / Off) ───────── */
function NeuToggle({ on, onChange, label, ariaLabel }) {
  return (
    <button
      className="btn"
      onClick={() => onChange(!on)}
      role="switch"
      aria-checked={on}
      aria-label={ariaLabel || label || (on ? 'On' : 'Off')}
      style={{
        height: 34, padding: '0 6px 0 14px', display: 'inline-flex', alignItems: 'center', gap: 10,
        fontSize: 12, fontWeight: 600, color: on ? 'var(--ink-1)' : 'var(--ink-3)',
        boxShadow: on
          ? 'inset -2px -2px 4px var(--hl), inset 2px 2px 4px var(--sh)'
          : '-2px -2px 4px var(--hl), 2px 2px 4px var(--sh)',
      }}
    >
      <span>{label || (on ? 'On' : 'Off')}</span>
      <span style={{
        width: 24, height: 24, borderRadius: '50%',
        display: 'grid', placeItems: 'center',
        background: 'var(--bg)',
        color: on ? 'oklch(0.7 0.1 var(--accent-h))' : 'var(--ink-3)',
        boxShadow: on
          ? '-1.5px -1.5px 3px var(--hl), 1.5px 1.5px 3px var(--sh), inset 0 0 0 1.5px currentColor'
          : '-1.5px -1.5px 3px var(--hl), 1.5px 1.5px 3px var(--sh)',
      }}>
        <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
          <path d="M5 1v4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/>
          <path d="M2.2 3.2a3.5 3.5 0 105.6 0" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" fill="none"/>
        </svg>
      </span>
    </button>
  );
}

/* ───────── Icon button ───────── */
function IconBtn({ children, onClick, size = 44, style, active, ariaLabel, title }) {
  return (
    <button
      className="btn icon-btn"
      onClick={onClick}
      aria-label={ariaLabel || title}
      aria-pressed={active ? true : undefined}
      title={title}
      style={{
        width: size, height: size,
        color: active ? 'oklch(0.68 0.09 var(--accent-h))' : 'var(--ink-2)',
        boxShadow: active
          ? 'inset -2px -2px 4px var(--hl), inset 2px 2px 4px var(--sh)'
          : '-2px -2px 4px var(--hl), 2px 2px 4px var(--sh)',
        ...style,
      }}
    >
      {children}
    </button>
  );
}

/* ───────── Neumorphic vertical slider (volume) ───────── */
function NeuVerticalSlider({ value, onChange, height = 90 }) {
  const trackRef = useRef(null);
  const drag = useRef(false);

  const update = (clientY) => {
    const r = trackRef.current.getBoundingClientRect();
    const v = 1 - Math.max(0, Math.min(1, (clientY - r.top) / r.height));
    onChange(v);
  };
  const onDown = (e) => {
    drag.current = true;
    const cy = e.touches ? e.touches[0].clientY : e.clientY;
    update(cy);
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    window.addEventListener('touchmove', onMove, { passive: false });
    window.addEventListener('touchend', onUp);
  };
  const onMove = (e) => {
    if (!drag.current) return;
    if (e.touches) e.preventDefault();
    const cy = e.touches ? e.touches[0].clientY : e.clientY;
    update(cy);
  };
  const onUp = () => {
    drag.current = false;
    window.removeEventListener('mousemove', onMove);
    window.removeEventListener('mouseup', onUp);
    window.removeEventListener('touchmove', onMove);
    window.removeEventListener('touchend', onUp);
  };

  return (
    <div
      ref={trackRef}
      onMouseDown={onDown}
      onTouchStart={onDown}
      style={{
        width: 16, height, borderRadius: 999,
        background: 'var(--bg)',
        boxShadow: 'inset -2px -2px 4px var(--hl), inset 2px 2px 4px var(--sh)',
        position: 'relative', cursor: 'pointer',
        touchAction: 'none',
      }}
    >
      {/* fill */}
      <div style={{
        position: 'absolute', left: 2, right: 2, bottom: 2,
        height: `calc(${value * 100}% - 4px)`,
        borderRadius: 999,
        background: 'linear-gradient(to top, oklch(0.72 0.1 var(--accent-h)), oklch(0.82 0.06 var(--accent-h)))',
        opacity: value > 0 ? 1 : 0,
        transition: 'opacity 200ms',
      }} />
    </div>
  );
}

/* ───────── Horizontal slider ───────── */
function NeuSlider({ value, onChange, min = 0, max = 1, step = 0.01 }) {
  return (
    <input
      type="range"
      className="neu-range"
      min={min} max={max} step={step} value={value}
      onChange={(e) => onChange(parseFloat(e.target.value))}
    />
  );
}

/* ───────── Half-circle timer gauge (hero) ───────── */
function TimerGauge({ minutes, active, running, remaining }) {
  // minutes: selected total (0, 15, 30, 60, 480)
  // remaining: seconds remaining (if running)
  const W = 260, H = 150;
  const cx = W / 2, cy = H - 10, r = 110, r2 = 128;

  // sweep progress: 0 → 1 based on remaining/total
  const pct = running && minutes > 0 ? (remaining / (minutes * 60)) : (active ? 1 : 0.55);

  // angular positions
  const start = Math.PI, end = 0; // left → right (top half)
  const theta = start + (end - start) * (1 - pct);
  const tipX = cx + r2 * Math.cos(theta);
  const tipY = cy + r2 * Math.sin(theta);

  // tick marks
  const ticks = [];
  const TICK_COUNT = 56;
  for (let i = 0; i <= TICK_COUNT; i++) {
    const t = i / TICK_COUNT;
    const a = start + (end - start) * t;
    const x1 = cx + r * Math.cos(a), y1 = cy + r * Math.sin(a);
    const major = i % 7 === 0;
    const len = major ? 16 : (i % 2 === 0 ? 10 : 6);
    const x2 = cx + (r + len) * Math.cos(a);
    const y2 = cy + (r + len) * Math.sin(a);
    const lit = t <= (1 - pct) + 0.001;
    ticks.push(
      <line key={i} x1={x1} y1={y1} x2={x2} y2={y2}
        stroke={lit ? 'var(--ink-3)' : 'var(--ink-1)'}
        strokeOpacity={lit ? 0.3 : 0.95}
        strokeWidth={major ? 2 : 1}
        strokeLinecap="round"
      />
    );
  }

  const label = minutes === 0 ? 'Off'
    : minutes >= 60 ? `${Math.floor(minutes/60)}h${minutes%60?` ${minutes%60}m`:''}`
    : `${minutes}m`;

  const sub = running
    ? formatRemaining(remaining)
    : active ? 'Ready' : 'Tap to set';

  return (
    <div style={{ position: 'relative', width: W, height: H + 40 }}>
      <svg width={W} height={H + 10} viewBox={`0 0 ${W} ${H + 10}`} style={{ display: 'block' }}>
        {/* soft arc track */}
        <path
          d={`M ${cx - r} ${cy} A ${r} ${r} 0 0 1 ${cx + r} ${cy}`}
          stroke="var(--ink-3)" strokeOpacity="0.15" strokeWidth="1" fill="none"
        />
        {ticks}
        {/* indicator dot */}
        <circle cx={tipX} cy={tipY} r="5" fill="var(--ink-1)" />
        <circle cx={tipX} cy={tipY} r="2" fill="var(--bg)" />
      </svg>
      {/* center readout */}
      <div style={{
        position: 'absolute', top: H - 58, left: 0, right: 0,
        textAlign: 'center',
      }}>
        <div style={{ fontSize: 34, fontWeight: 700, letterSpacing: '-0.03em', color: 'var(--ink-1)' }} className="t-num">{label}</div>
        <div className="t-label" style={{ marginTop: 2 }}>{sub}</div>
      </div>
      {/* edge labels */}
      <div style={{ position: 'absolute', left: 10, bottom: 16, fontSize: 11, color: 'var(--ink-3)' }}>15m</div>
      <div style={{ position: 'absolute', right: 10, bottom: 16, fontSize: 11, color: 'var(--ink-3)' }}>8h</div>
    </div>
  );
}

function formatRemaining(sec) {
  if (sec <= 0) return 'Done';
  const h = Math.floor(sec / 3600);
  const m = Math.floor((sec % 3600) / 60);
  const s = Math.floor(sec % 60);
  if (h > 0) return `${h}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')} left`;
  return `${m}:${String(s).padStart(2,'0')} left`;
}

/* ───────── Section header ───────── */
function SectionHead({ title, action }) {
  return (
    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', padding: '0 4px' }}>
      <div className="t-label">{title}</div>
      {action}
    </div>
  );
}

Object.assign(window, {
  NeuToggle, IconBtn, NeuVerticalSlider, NeuSlider, TimerGauge, SectionHead, formatRemaining,
});
