// components.jsx — SaveHor primitive components.
// All consume an active palette `c` (theme object) passed in, so palette
// tweaks reflow the whole app. Type comes from a `font` var on parent.

const Btn = ({ kind = 'primary', size = 'md', icon, iconR, full, children, c, disabled, onClick, style }) => {
  const sizes = {
    sm: { h: 36, px: 14, fs: 14, rad: 10 },
    md: { h: 48, px: 18, fs: 15, rad: 12 },
    lg: { h: 56, px: 22, fs: 16, rad: 14 },
  }[size];
  const palette = {
    primary:    { bg: c.primary, fg: '#fff', bd: 'transparent', sh: '0 1px 0 rgba(0,0,0,0.04), 0 4px 10px rgba(46,107,74,0.18)' },
    secondary:  { bg: c.surface, fg: c.text, bd: c.border, sh: '0 1px 0 rgba(0,0,0,0.02)' },
    tertiary:   { bg: 'transparent', fg: c.text, bd: 'transparent', sh: 'none' },
    accent:     { bg: c.accent, fg: '#fff', bd: 'transparent', sh: '0 1px 0 rgba(0,0,0,0.04), 0 4px 10px rgba(194,130,88,0.22)' },
    danger:     { bg: c.danger, fg: '#fff', bd: 'transparent', sh: 'none' },
    ghost:      { bg: c.primarySoft, fg: c.primaryDk, bd: 'transparent', sh: 'none' },
  }[kind];
  return (
    <button onClick={onClick} disabled={disabled}
      style={{
        height: sizes.h, padding: `0 ${sizes.px}px`, borderRadius: sizes.rad,
        background: disabled ? c.surfaceAlt : palette.bg,
        color: disabled ? c.textLight : palette.fg,
        border: `1px solid ${palette.bd}`,
        boxShadow: disabled ? 'none' : palette.sh,
        fontWeight: 600, fontSize: sizes.fs, fontFamily: 'inherit', letterSpacing: -0.1,
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
        width: full ? '100%' : undefined, cursor: disabled ? 'not-allowed' : 'pointer',
        transition: 'transform .08s, box-shadow .12s', flexShrink: 0, ...style,
      }}>
      {icon}<span>{children}</span>{iconR}
    </button>
  );
};

const Card = ({ kind = 'default', children, c, style, onClick }) => {
  const styles = {
    default:     { bg: c.surface, bd: c.borderSoft, sh: '0 1px 0 rgba(20,30,25,0.03), 0 6px 18px rgba(20,30,25,0.04)' },
    flat:        { bg: c.surface, bd: c.border, sh: 'none' },
    highlighted: { bg: c.primarySoft, bd: c.primary + '33', sh: 'none' },
    tinted:      { bg: c.surfaceAlt, bd: c.border, sh: 'none' },
    sand:        { bg: c.sand, bd: 'transparent', sh: 'none' },
    sky:         { bg: c.skySoft, bd: 'transparent', sh: 'none' },
    accent:      { bg: c.accentSoft, bd: 'transparent', sh: 'none' },
  }[kind];
  return (
    <div onClick={onClick} style={{
      background: styles.bg, borderRadius: 20,
      border: `1px solid ${styles.bd}`, boxShadow: styles.sh,
      cursor: onClick ? 'pointer' : 'default', ...style,
    }}>{children}</div>
  );
};

const Field = ({ label, helper, value, onChange, suffix, prefix, error, success, type = 'text', placeholder, c, style }) => {
  const bd = error ? c.danger : success ? c.good : c.border;
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 6, ...style }}>
      {label && <span style={{ fontSize: 13, fontWeight: 500, color: c.textMuted, letterSpacing: -0.05 }}>{label}</span>}
      <div style={{
        display: 'flex', alignItems: 'center', height: 56, padding: '0 16px',
        background: c.surface, border: `1.5px solid ${bd}`, borderRadius: 14,
        gap: 8,
      }}>
        {prefix && <span style={{ color: c.textLight, fontSize: 16, fontWeight: 500 }}>{prefix}</span>}
        <input value={value} onChange={onChange} type={type} placeholder={placeholder}
          style={{
            flex: 1, border: 'none', outline: 'none', background: 'transparent',
            fontFamily: 'inherit', fontSize: 17, fontWeight: 500, color: c.text,
            minWidth: 0, padding: 0,
          }} />
        {suffix && <span style={{ color: c.textLight, fontSize: 15, fontWeight: 500 }}>{suffix}</span>}
      </div>
      {(helper || error) && (
        <span style={{ fontSize: 12.5, color: error ? c.danger : c.textLight, fontWeight: 500, lineHeight: 1.4 }}>
          {error || helper}
        </span>
      )}
    </label>
  );
};

const Chip = ({ tone = 'neutral', size = 'md', children, icon, c, style }) => {
  const tones = {
    neutral: { bg: c.surfaceAlt, fg: c.textMuted },
    primary: { bg: c.primarySoft, fg: c.primaryDk },
    accent:  { bg: c.accentSoft, fg: '#8A5A1E' },
    sand:    { bg: c.sand, fg: '#5A4A22' },
    sky:     { bg: c.skySoft, fg: '#345070' },
    good:    { bg: c.goodSoft, fg: '#2F6147' },
    warn:    { bg: c.warnSoft, fg: '#7C5A1B' },
    danger:  { bg: c.dangerSoft, fg: '#7A2A1F' },
  }[tone];
  const sz = size === 'sm' ? { h: 22, px: 8, fs: 11.5 } : { h: 26, px: 10, fs: 12.5 };
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      height: sz.h, padding: `0 ${sz.px}px`, borderRadius: 999,
      background: tones.bg, color: tones.fg,
      fontSize: sz.fs, fontWeight: 600, letterSpacing: 0.1, lineHeight: 1, ...style,
    }}>
      {icon}{children}
    </span>
  );
};

// Progress ring — uses primary green; supports over-budget tinting via tone.
const Ring = ({ value, max = 100, size = 180, stroke = 14, c, tone = 'primary', children }) => {
  const r = (size - stroke) / 2;
  const cx = size / 2;
  const circ = 2 * Math.PI * r;
  const pct = Math.min(1, value / max);
  const dash = circ * pct;
  const colors = { primary: c.primary, warn: c.warn, danger: c.danger, good: c.good };
  return (
    <div style={{ position: 'relative', width: size, height: size, flexShrink: 0 }}>
      <svg width={size} height={size}>
        <circle cx={cx} cy={cx} r={r} fill="none" stroke={c.borderSoft} strokeWidth={stroke} />
        <circle cx={cx} cy={cx} r={r} fill="none" stroke={colors[tone]} strokeWidth={stroke}
          strokeLinecap="round" strokeDasharray={`${dash} ${circ}`}
          transform={`rotate(-90 ${cx} ${cx})`}
          style={{ transition: 'stroke-dasharray .4s ease' }} />
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column' }}>
        {children}
      </div>
    </div>
  );
};

// BudgetBattery — daily budget shown as a draining battery.
// `remaining`/`budget` in dollars; `dayFraction` 0..1 marks where "now" is so
// the user can see if they're ahead of (left of) or behind (right of) pace.
const BudgetBattery = ({ c, remaining, budget, dayFraction = 0.5, height = 84 }) => {
  const pct = Math.max(0, Math.min(1, remaining / budget));
  const usedFraction = 1 - pct;
  // Level-based color: healthy green → amber under 30% → red under 12%.
  // Direct "how full is the tank" read, like a fuel gauge.
  const level = pct <= 0 ? 'empty' : pct < 0.12 ? 'critical' : pct < 0.30 ? 'low' : 'ok';
  const empty = remaining <= 0;
  // Solid fill — the COLOUR changes as the level drops (green → amber → red).
  const fillGrad = { ok: c.primary, low: c.warn, critical: c.danger, empty: c.danger }[level];
  const fill = fillGrad;
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 7, width: '100%' }}>
      {/* battery body */}
      <div style={{
        flex: 1, height, position: 'relative',
        background: c.surfaceAlt, border: `2.5px solid ${c.border}`,
        borderRadius: 18, overflow: 'hidden', boxSizing: 'border-box',
      }}>
        {/* fill */}
        <div style={{
          position: 'absolute', top: 4, bottom: 4, left: 4,
          width: `calc(${pct * 100}% - 8px)`, minWidth: pct > 0 ? 12 : 0,
          background: fillGrad, borderRadius: 12,
          transition: 'width .6s cubic-bezier(.3,.7,.4,1), background .4s',
        }} />
        {/* low-level pulse dot near the tip when critical */}
        {level === 'critical' && (
          <div className="m-glow" style={{
            position: 'absolute', top: 0, bottom: 0, left: `calc(${pct * 100}% - 4px)`,
            width: 4, borderRadius: 2, background: c.danger,
          }} />
        )}
        {/* segment ticks */}
        {[0.25, 0.5, 0.75].map(s => (
          <div key={s} style={{
            position: 'absolute', top: 10, bottom: 10, left: `${s * 100}%`,
            width: 1.5, background: c.border, opacity: 0.5, borderRadius: 1,
          }} />
        ))}
        {/* lightning glyph inside fill when healthy */}
        <div style={{ position: 'absolute', left: 14, top: '50%', transform: 'translateY(-50%)', display: 'flex', alignItems: 'center', gap: 6 }}>
          <div style={{ width: 26, height: 26, borderRadius: 8, background: 'rgba(255,255,255,0.25)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <IcBolt size={16} color="#fff" />
          </div>
        </div>
      </div>
      {/* terminal nub */}
      <div style={{ width: 7, height: height * 0.42, background: c.border, borderRadius: 3, flexShrink: 0 }} />
    </div>
  );
};

// Linear meter bar — for weekly + secondary contexts.
const Bar = ({ value, max = 100, c, tone = 'primary', height = 8, bg }) => {
  const colors = { primary: c.primary, warn: c.warn, danger: c.danger, good: c.good, sky: c.sky, accent: c.accent };
  return (
    <div style={{ height, background: bg || c.borderSoft, borderRadius: 999, overflow: 'hidden' }}>
      <div style={{ width: Math.min(100, (value / max) * 100) + '%', height: '100%', background: colors[tone], borderRadius: 999, transition: 'width .4s' }} />
    </div>
  );
};

// Toast — shown on missions complete etc.
const Toast = ({ icon, title, sub, c }) => (
  <div style={{
    background: c.text, color: '#fff', borderRadius: 16,
    padding: '14px 18px', display: 'flex', alignItems: 'center', gap: 12,
    boxShadow: '0 10px 32px rgba(0,0,0,0.2)', minWidth: 280,
  }}>
    <div style={{
      width: 36, height: 36, borderRadius: 10, background: c.primary,
      display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
    }}>{icon}</div>
    <div style={{ flex: 1 }}>
      <div style={{ fontSize: 14.5, fontWeight: 600, letterSpacing: -0.1 }}>{title}</div>
      {sub && <div style={{ fontSize: 12.5, opacity: 0.7, marginTop: 1 }}>{sub}</div>}
    </div>
  </div>
);

// Tab bar — bottom navigation, 3 tabs. Generous hit areas, mascot-light.
const TabBar = ({ active, onChange, c }) => {
  const tabs = [
    { id: 'home',     label: 'Home',     Icon: IcHome },
    { id: 'play',     label: 'Play',     Icon: IcMission },
    { id: 'analysis', label: 'Analysis', Icon: IcChart },
    { id: 'you',      label: 'You',      Icon: IcUsers },
  ];
  return (
    <div style={{
      position: 'absolute', bottom: 0, left: 0, right: 0,
      paddingBottom: 24, paddingTop: 10,
      background: c.surface,
      borderTop: `1px solid ${c.borderSoft}`,
      display: 'flex', justifyContent: 'space-around', zIndex: 30,
    }}>
      {tabs.map(t => {
        const on = active === t.id;
        return (
          <button key={t.id} onClick={() => onChange?.(t.id)}
            style={{
              border: 'none', background: 'transparent', cursor: 'pointer',
              display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
              padding: '6px 14px 4px', flex: 1, minWidth: 0,
              color: on ? c.primary : c.navInactive,
              fontFamily: 'inherit', position: 'relative',
            }}>
            <div style={{
              width: 52, height: 30, borderRadius: 15,
              background: on ? c.primarySoft : 'transparent',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              transition: 'background .2s',
            }}>
              <t.Icon size={22} color={on ? c.primary : c.navInactive} />
            </div>
            <span style={{ fontSize: 11, fontWeight: on ? 700 : 500, letterSpacing: 0.1 }}>{t.label}</span>
          </button>
        );
      })}
    </div>
  );
};

// Header bar — used inside screens (not iPhone status bar).
const Header = ({ left, title, right, c, sub, big }) => (
  <div style={{ padding: '14px 20px 10px', background: 'transparent' }}>
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, minHeight: 36 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>{left}</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>{right}</div>
    </div>
    {big && <div style={{ fontSize: 28, fontWeight: 700, color: c.text, letterSpacing: -0.5, marginTop: 6 }}>{title}</div>}
    {sub && <div style={{ fontSize: 13, color: c.textLight, marginTop: 2 }}>{sub}</div>}
  </div>
);

// Stepper — onboarding progress dots.
const Stepper = ({ step, total, c }) => (
  <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
    {Array.from({ length: total }).map((_, i) => (
      <div key={i} style={{
        height: 4, borderRadius: 2,
        width: i === step ? 28 : 10,
        background: i <= step ? c.primary : c.borderSoft,
        transition: 'all .25s',
      }} />
    ))}
  </div>
);

// Sparkline — used in trend strips.
const Sparkline = ({ data, w = 80, h = 30, color, fillColor }) => {
  const max = Math.max(...data, 1);
  const min = Math.min(...data, 0);
  const range = max - min || 1;
  const dx = w / (data.length - 1);
  const pts = data.map((v, i) => [i * dx, h - ((v - min) / range) * (h - 4) - 2]);
  const d = pts.map((p, i) => (i === 0 ? `M${p[0]},${p[1]}` : `L${p[0]},${p[1]}`)).join(' ');
  const fill = `${d} L${w},${h} L0,${h} Z`;
  return (
    <svg width={w} height={h}>
      {fillColor && <path d={fill} fill={fillColor} />}
      <path d={d} fill="none" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
};

Object.assign(window, { Btn, Card, Field, Chip, Ring, BudgetBattery, Bar, Toast, TabBar, Header, Stepper, Sparkline });
