// Reusable components

function Pill({ children, kind = '', className = '' }) {
  return <span className={`pill ${kind} ${className}`}>{children}</span>;
}

function PhasePill({ phase }) {
  const key = phase.replace(/\s+/g, '');
  return <span className={`pill phase-${key}`}>{phase}</span>;
}

function TypePill({ type }) {
  return <span className={`pill type-${type}`} style={{background:'transparent', borderColor:'transparent', padding:'4px 9px'}}>
    <span style={{display:'inline-block',width:'6px',height:'6px',borderRadius:'50%',background:'currentColor',marginRight:'4px'}}></span>
    {type}
  </span>;
}

function Check({ on, onClick, size = 18 }) {
  return <button
    className={`check ${on ? 'on' : ''}`}
    onClick={onClick}
    style={{width: size, height: size}}
    aria-label={on ? 'Done' : 'Mark done'}
  />;
}

function Bar({ value, total, showLabel = false }) {
  const pct = total ? Math.min(100, (value/total)*100) : 0;
  return (
    <div style={{display:'flex',alignItems:'center',gap:'10px'}}>
      <div className="bar grow"><div className="bar-fill" style={{width: `${pct}%`}}/></div>
      {showLabel && <span className="mono" style={{fontSize:'11px',color:'var(--ink-2)',minWidth:'52px',textAlign:'right'}}>{value}/{total}</span>}
    </div>
  );
}

function Stat({ label, value, sub, accent }) {
  return (
    <div className="card" style={{padding:'18px 20px'}}>
      <div className="kicker">{label}</div>
      <div style={{
        fontFamily:'var(--serif)',
        fontSize: '40px',
        lineHeight: 1,
        letterSpacing:'-0.02em',
        color: accent ? 'var(--accent)' : 'var(--ink)',
        margin: '6px 0 4px'
      }}>{value}</div>
      {sub && <div className="mono muted" style={{fontSize:'10px',letterSpacing:'0.06em'}}>{sub}</div>}
    </div>
  );
}

// Animated number
function CountUp({ to, duration = 800, format = (v) => v }) {
  const [val, setVal] = React.useState(0);
  React.useEffect(() => {
    const start = performance.now();
    let raf;
    function tick(now) {
      const t = Math.min(1, (now - start) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setVal(Math.round(to * eased));
      if (t < 1) raf = requestAnimationFrame(tick);
    }
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [to, duration]);
  return <span>{format(val)}</span>;
}

// SVG sparkline: takes array of numbers, renders inline
function Sparkline({ values, width = 160, height = 36, stroke = 'var(--accent)', fill = true, threshold }) {
  if (!values || values.length === 0) {
    return <div className="mono muted" style={{fontSize:'10px'}}>no data yet</div>;
  }
  const pad = 3;
  const w = width, h = height;
  const min = Math.min(...values, threshold ?? Infinity);
  const max = Math.max(...values, threshold ?? -Infinity);
  const range = max - min || 1;
  const stepX = values.length > 1 ? (w - pad * 2) / (values.length - 1) : 0;
  const points = values.map((v, i) => {
    const x = pad + i * stepX;
    const y = h - pad - ((v - min) / range) * (h - pad * 2);
    return [x, y];
  });
  const path = points.map((p, i) => (i === 0 ? `M${p[0]},${p[1]}` : `L${p[0]},${p[1]}`)).join(' ');
  const area = `${path} L${points[points.length-1][0]},${h-pad} L${points[0][0]},${h-pad} Z`;
  const thresholdY = threshold != null ? h - pad - ((threshold - min) / range) * (h - pad * 2) : null;
  return (
    <svg width={w} height={h} style={{display:'block'}}>
      {fill && <path d={area} fill={stroke} opacity="0.12" />}
      {thresholdY != null && (
        <line x1={pad} x2={w-pad} y1={thresholdY} y2={thresholdY}
          stroke="var(--ink-3)" strokeDasharray="2 3" strokeWidth="1" opacity="0.6"/>
      )}
      <path d={path} stroke={stroke} strokeWidth="1.5" fill="none" strokeLinejoin="round" strokeLinecap="round"/>
      {points.map((p, i) => (
        <circle key={i} cx={p[0]} cy={p[1]} r="2.5" fill={stroke} />
      ))}
    </svg>
  );
}

// Compact 1-5 rating row, click to set
function Rating({ value, onChange, max = 5, color = 'var(--accent)' }) {
  return (
    <div style={{display:'inline-flex',gap:'4px'}}>
      {Array.from({length: max}, (_, i) => {
        const on = (value || 0) > i;
        return (
          <button
            key={i}
            onClick={() => onChange(value === i + 1 ? 0 : i + 1)}
            aria-label={`${i+1} of ${max}`}
            style={{
              width: 14, height: 14, borderRadius: '50%',
              border: `1.5px solid ${on ? color : 'var(--line)'}`,
              background: on ? color : 'transparent',
              transition: 'all 0.12s',
            }}
          />
        );
      })}
    </div>
  );
}

// Streak ring: shows current streak length inside a ring
function StreakRing({ count, goal = 7, size = 56, color = 'var(--accent)' }) {
  const r = size / 2 - 4;
  const circ = 2 * Math.PI * r;
  const pct = Math.min(1, count / goal);
  return (
    <div style={{position:'relative', width:size, height:size, display:'inline-block'}}>
      <svg width={size} height={size} style={{transform:'rotate(-90deg)'}}>
        <circle cx={size/2} cy={size/2} r={r}
          stroke="var(--line-soft)" strokeWidth="3" fill="none"/>
        <circle cx={size/2} cy={size/2} r={r}
          stroke={color} strokeWidth="3" fill="none"
          strokeDasharray={circ}
          strokeDashoffset={circ * (1 - pct)}
          strokeLinecap="round"
          style={{transition:'stroke-dashoffset 0.5s cubic-bezier(0.2,0.8,0.2,1)'}}/>
      </svg>
      <div style={{
        position:'absolute', inset:0, display:'flex', alignItems:'center',
        justifyContent:'center', fontFamily:'var(--serif)', fontSize:'20px', lineHeight:1,
      }}>{count}</div>
    </div>
  );
}

Object.assign(window, { Pill, PhasePill, TypePill, Check, Bar, Stat, CountUp, Sparkline, Rating, StreakRing });
