/* ───────────────────────────────────────────────
   Happy Guts — shared UI
   Exposed: Icon, CompoundBar, CompoundRow, VerdictPill,
   VerdictDot, YesNoMaybe, FoodTile, TopBar, Segmented, Sheet
   ─────────────────────────────────────────────── */

/* ── line-icon set (simple geometric strokes) ── */
function Icon({ name, size = 24, color = 'currentColor', strokeWidth = 2, style }) {
  const p = { fill: 'none', stroke: color, strokeWidth, strokeLinecap: 'round', strokeLinejoin: 'round' };
  const paths = {
    home:    <><path {...p} d="M4 11.5 12 4l8 7.5" /><path {...p} d="M6 10v9h12v-9" /></>,
    foods:   <><path {...p} d="M12 8c0-3 2-4 4-4 0 3-1.5 4-4 4Z"/><path {...p} d="M12 8c-1-3-3.5-3.5-6-3 .5 3 3 4 6 3.5Z"/><path {...p} d="M5.5 11c0-1.5 2.5-2 6.5-2s6.5.5 6.5 2c0 5-2.5 9-6.5 9S5.5 16 5.5 11Z"/></>,
    recipes: <><path {...p} d="M5 4h11a3 3 0 0 1 3 3v13H8a3 3 0 0 1-3-3Z"/><path {...p} d="M19 17H8a3 3 0 0 0-3 3"/><path {...p} d="M9 8h6M9 11h4"/></>,
    list:    <><rect {...p} x="5" y="4" width="14" height="17" rx="2.5"/><path {...p} d="M9 3v3h6V3"/><path {...p} d="M9 11l1.5 1.5L13 10M9 16l1.5 1.5L13 15"/></>,
    scan:    <><path {...p} d="M4 8V6a2 2 0 0 1 2-2h2M16 4h2a2 2 0 0 1 2 2v2M20 16v2a2 2 0 0 1-2 2h-2M8 20H6a2 2 0 0 1-2-2v-2"/><path {...p} d="M7.5 8.5v7M10 8.5v7M12.5 8.5v7M16.5 8.5v7M14.5 8.5v7"/></>,
    settings:<><circle {...p} cx="12" cy="12" r="3"/><path {...p} d="M12 2.5v3M12 18.5v3M21.5 12h-3M5.5 12h-3M18.5 5.5l-2 2M7.5 16.5l-2 2M18.5 18.5l-2-2M7.5 7.5l-2-2"/></>,
    sliders: <><path {...p} d="M5 8h9M18 8h1M5 16h1M10 16h9"/><circle {...p} cx="16" cy="8" r="2.2"/><circle {...p} cx="8" cy="16" r="2.2"/></>,
    search:  <><circle {...p} cx="11" cy="11" r="6.5"/><path {...p} d="m16 16 4 4"/></>,
    chevR:   <path {...p} d="m9 6 6 6-6 6"/>,
    chevL:   <path {...p} d="m15 6-6 6 6 6"/>,
    chevD:   <path {...p} d="m6 9 6 6 6-6"/>,
    plus:    <path {...p} d="M12 5v14M5 12h14"/>,
    check:   <path {...p} d="m5 12.5 4.5 4.5L19 7"/>,
    bell:    <><path {...p} d="M6 9a6 6 0 0 1 12 0c0 5 1.5 6 2 7H4c.5-1 2-2 2-7Z"/><path {...p} d="M10 20a2 2 0 0 0 4 0"/></>,
    x:       <path {...p} d="M6 6l12 12M18 6 6 18"/>,
    edit:    <><path {...p} d="M5 19h14"/><path {...p} d="M14 5.5 18.5 10 9 19.5 4 21l1.5-5Z"/></>,
    info:    <><circle {...p} cx="12" cy="12" r="9"/><path {...p} d="M12 11v5M12 8h.01"/></>,
    star:    <path {...p} d="M12 4.5l2.3 4.8 5.2.7-3.8 3.6 1 5.1L12 16.4 7.3 18.7l1-5.1L4.5 10l5.2-.7Z"/>,
    arrowR:  <path {...p} d="M5 12h14M13 6l6 6-6 6"/>,
    clock:   <><circle {...p} cx="12" cy="12" r="8.5"/><path {...p} d="M12 7.5V12l3 2"/></>,
    leaf:    <><path {...p} d="M5 19C4 11 9 5 19 5c0 10-6 15-14 14Z"/><path {...p} d="M5 19c3-5 6-7 10-9"/></>,
    flame:   <><path {...p} d="M12 3c4 4 5 7 5 10a5 5 0 0 1-10 0c0-1 .5-2.5 1.5-3.5C9 11 10 12 10 12c0-3 1-6 2-9Z"/></>,
    plate:   <><circle {...p} cx="12" cy="12" r="8.5"/><circle {...p} cx="12" cy="12" r="4"/></>,
    trash:   <><path {...p} d="M5 7h14M10 7V5h4v2M6 7l1 13h10l1-13"/></>,
    image:   <><rect {...p} x="3" y="5" width="18" height="14" rx="2.5"/><circle {...p} cx="8.5" cy="10" r="1.5"/><path {...p} d="M21 15.5 16 11l-4 4-2-2-4 4"/></>,
    // install + scan
    download:<><path {...p} d="M12 4v11M7.5 10.5 12 15l4.5-4.5"/><path {...p} d="M5 19h14"/></>,
    share:   <><path {...p} d="M12 3.5v11M8 7.5l4-4 4 4"/><path {...p} d="M8.5 10.5H7a2 2 0 0 0-2 2V19a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6.5a2 2 0 0 0-2-2h-1.5"/></>,
    addBox:  <><rect {...p} x="4" y="4" width="16" height="16" rx="3.5"/><path {...p} d="M12 8.5v7M8.5 12h7"/></>,
    more:    <><circle cx="12" cy="5.5" r="1.6" fill={color}/><circle cx="12" cy="12" r="1.6" fill={color}/><circle cx="12" cy="18.5" r="1.6" fill={color}/></>,
    moreH:   <><circle cx="5.5" cy="12" r="1.6" fill={color}/><circle cx="12" cy="12" r="1.6" fill={color}/><circle cx="18.5" cy="12" r="1.6" fill={color}/></>,
    copy:    <><rect {...p} x="8.5" y="8.5" width="11" height="11" rx="2.5"/><path {...p} d="M15.5 8.5V6.5a2 2 0 0 0-2-2h-7a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h2"/></>,
    camera:  <><path {...p} d="M4 8.5a2 2 0 0 1 2-2h2l1.5-2h5L16 6.5h2a2 2 0 0 1 2 2V18a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Z"/><circle {...p} cx="12" cy="13" r="3.5"/></>,
    keyboard:<><rect {...p} x="3" y="6" width="18" height="12" rx="2.5"/><path {...p} d="M7 10h.01M10.5 10h.01M14 10h.01M17.5 10h.01M7 14h.01M17.5 14h.01M10 14h4"/></>,
    flash:   <path {...p} d="M13 3 5.5 13.5H12L11 21l7.5-10.5H12Z"/>,
    offline: <><path {...p} d="M4 4l16 16"/><path {...p} d="M8.5 8.8A9 9 0 0 0 3 11.5M12 7.5a12 12 0 0 1 9 4M6 15a6 6 0 0 1 4-2M14.5 13.2A6 6 0 0 1 18 15M12 19h.01"/></>,
    external:<><path {...p} d="M14 4h6v6M20 4l-9 9"/><path {...p} d="M18 14v4a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4"/></>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" style={style} aria-hidden="true">
      {paths[name] || null}
    </svg>
  );
}

/* ── compound level bar (5 segments, rising ramp) ── */
function CompoundBar({ level, muted = false, maybe = false, height = 8 }) {
  const unknown = window.isUnknown(level);
  // Unknown: every segment grey — no position on the ramp.
  const ramp = unknown ? Array(5).fill('var(--lv-unknown)')
    : ['var(--lv-nil)','var(--lv-low)','var(--lv-med)','var(--lv-high)','var(--lv-vhigh)'];
  const filled = unknown ? 5 : (window.LEVEL_VALUE[level]) + 1; // Nil=1 … V.High=5
  return (
    <div style={{ display: 'flex', gap: 3, flex: 1 }}>
      {ramp.map((c, i) => {
        const on = i < filled;
        let bg = 'var(--lv-off)';
        if (on) bg = muted ? 'var(--line-2)' : c;
        return (
          <div key={i} style={{
            flex: 1, height, borderRadius: 99, backgroundColor: bg,
            opacity: on ? (maybe ? 0.55 : 1) : 1,
            backgroundImage: (on && maybe)
              ? 'repeating-linear-gradient(45deg, rgba(255,255,255,.6) 0 2px, transparent 2px 5px)'
              : 'none',
            transition: 'background .2s',
          }} />
        );
      })}
    </div>
  );
}

/* ── one compound row: name + bar + level label ── */
function CompoundRow({ c, level, setting, compact = false }) {
  const inactive = setting === 'no';
  const meta = window.levelMeta(level);
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, opacity: inactive ? 0.45 : 1 }}>
      <div style={{ width: compact ? 74 : 92, flexShrink: 0, display: 'flex', alignItems: 'center', gap: 6 }}>
        <span style={{ width: 8, height: 8, borderRadius: 99, background: `var(${c.cssVar})`, flexShrink: 0 }} />
        <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink-2)', whiteSpace: 'nowrap' }}>{c.name}</span>
      </div>
      <CompoundBar level={level} muted={inactive} maybe={setting === 'maybe'} />
      <span className="mono" style={{
        width: 56, flexShrink: 0, textAlign: 'right', fontSize: 12, fontWeight: 700,
        color: inactive ? 'var(--ink-3)' : meta.color,
      }}>{meta.label}</span>
    </div>
  );
}

/* ── verdict pill + dot ── */
function VerdictDot({ verdict, size = 10 }) {
  const m = window.VERDICT_META[verdict];
  return <span style={{ width: size, height: size, borderRadius: 99, background: m.color, flexShrink: 0, display: 'inline-block' }} />;
}
function VerdictPill({ verdict, big = false }) {
  const m = window.VERDICT_META[verdict];
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: big ? 8 : 6,
      background: m.tint, color: m.ink, fontWeight: 700,
      borderRadius: 999, padding: big ? '9px 16px 9px 12px' : '5px 11px 5px 9px',
      fontSize: big ? 15 : 12.5, lineHeight: 1, whiteSpace: 'nowrap',
    }}>
      <VerdictDot verdict={verdict} size={big ? 11 : 8} />
      {m.label}
    </span>
  );
}

/* ── Yes / Maybe / No control (setup) ── */
function YesNoMaybe({ value, onChange }) {
  const opts = [
    { v: 'yes',   label: 'Yes',   c: 'var(--avoid)',   t: 'var(--avoid-tint)',   ink: 'var(--avoid-ink)' },
    { v: 'maybe', label: 'Maybe', c: 'var(--caution)', t: 'var(--caution-tint)', ink: 'var(--caution-ink)' },
    { v: 'no',    label: 'No',    c: 'var(--safe)',    t: 'var(--safe-tint)',    ink: 'var(--safe-ink)' },
  ];
  return (
    <div style={{ display: 'flex', gap: 7 }}>
      {opts.map(o => {
        const on = value === o.v;
        return (
          <button key={o.v} className="btn" onClick={() => onChange(o.v)} style={{
            flex: 1, padding: '11px 0', fontSize: 14.5, fontWeight: 700,
            background: on ? o.c : o.t,
            color: on ? '#fff' : o.ink,
            boxShadow: on ? 'var(--shadow-1)' : 'none',
          }}>{o.label}</button>
        );
      })}
    </div>
  );
}

/* ── food image (with graceful placeholder) ──
   One square WebP per food (assets/foods/<base>.webp, 384×384) produced by
   scripts/optimize-images.mjs and reused at every size — list avatars and the
   detail thumbnail alike. `image_name` in the CSVs is the base name (no
   extension). Until the file exists (or on load error) a labelled placeholder
   keeps the layout final. `size` → square box; `fill` → fills the parent box. */
const FOOD_IMG_BASE = 'assets/foods/';
function foodImageBase(image) {
  return image ? String(image).replace(/\.[a-z0-9]+$/i, '') : null; // tolerate a stray extension
}
function FoodImage({ food, size, radius = 13, fill = false, label = false, style }) {
  const base = foodImageBase(food && food.image);
  const [broken, setBroken] = React.useState(false);
  React.useEffect(() => { setBroken(false); }, [base]);

  const box = {
    ...(fill ? { width: '100%', height: '100%' } : { width: size, height: size }),
    borderRadius: radius, flexShrink: 0, overflow: 'hidden', position: 'relative',
    display: 'flex', alignItems: 'center', justifyContent: 'center', ...style,
  };

  if (base && !broken) {
    return (
      <div style={{ ...box, background: 'var(--bg-2)' }}>
        <img src={`${FOOD_IMG_BASE}${base}.webp`} alt={food.name || ''}
          width={fill ? undefined : size} height={fill ? undefined : size}
          loading="lazy" decoding="async" onError={() => setBroken(true)}
          style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
      </div>
    );
  }
  // placeholder: striped slot + image glyph (+ optional base-name label)
  const glyph = fill ? 34 : Math.max(15, Math.round((size || 40) * 0.42));
  return (
    <div className="ph" style={box}>
      <Icon name="image" size={glyph} color="var(--ink-3)" strokeWidth={1.8} />
      {label && base && <span style={{ position: 'absolute', bottom: 10, right: 10 }}>{base}.webp</span>}
    </div>
  );
}

/* ── food tile avatar ── */
function FoodTile({ food, size = 46, radius = 13 }) {
  return <FoodImage food={food} size={size} radius={radius} />;
}

/* ── in-app top bar ── */
function TopBar({ title, onBack, right, sub, large = false }) {
  return (
    <div style={{ padding: large ? '6px 20px 8px' : '4px 16px 6px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, minHeight: 40 }}>
        {onBack && (
          <button className="btn" onClick={onBack} style={{
            width: 38, height: 38, background: 'var(--card)', boxShadow: 'var(--shadow-1)', marginLeft: -2,
          }}><Icon name="chevL" size={20} color="var(--ink)" /></button>
        )}
        <div style={{ flex: 1, minWidth: 0 }}>
          {sub && <div className="eyebrow" style={{ marginBottom: 2 }}>{sub}</div>}
          <h1 style={{ fontSize: large ? 30 : 20, color: 'var(--ink)' }}>{title}</h1>
        </div>
        {right}
      </div>
    </div>
  );
}

/* ── segmented filter control ── */
function Segmented({ options, value, onChange, small = false }) {
  return (
    <div style={{
      display: 'flex', gap: 4, background: 'var(--bg-2)', borderRadius: 999, padding: 4,
    }}>
      {options.map(o => {
        const v = typeof o === 'string' ? o : o.v;
        const label = typeof o === 'string' ? o : o.label;
        const on = value === v;
        return (
          <button key={v} className="btn" onClick={() => onChange(v)} style={{
            flex: 1, padding: small ? '7px 8px' : '9px 10px', fontSize: small ? 12.5 : 13.5, fontWeight: 700,
            background: on ? 'var(--card)' : 'transparent',
            color: on ? 'var(--ink)' : 'var(--ink-3)',
            boxShadow: on ? 'var(--shadow-1)' : 'none',
          }}>{label}</button>
        );
      })}
    </div>
  );
}

/* ── bottom sheet ── */
function Sheet({ open, onClose, children, title }) {
  if (!open) return null;
  return (
    <div onClick={onClose} style={{
      position: 'absolute', inset: 0, zIndex: 80, display: 'flex', alignItems: 'flex-end',
      background: 'rgba(30,22,14,.32)', backdropFilter: 'blur(2px)',
      animation: 'hgFade .2s ease',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', background: 'var(--bg)', borderRadius: '28px 28px 0 0',
        padding: '10px 20px 28px', boxShadow: '0 -10px 40px rgba(0,0,0,.2)',
        animation: 'hgUp .26s cubic-bezier(.2,.8,.2,1)', maxHeight: '82%', overflowY: 'auto',
      }}>
        <div style={{ width: 40, height: 5, borderRadius: 99, background: 'var(--line-2)', margin: '4px auto 14px' }} />
        {title && <h2 style={{ fontSize: 22, marginBottom: 14 }}>{title}</h2>}
        {children}
      </div>
    </div>
  );
}

Object.assign(window, {
  Icon, CompoundBar, CompoundRow, VerdictDot, VerdictPill,
  YesNoMaybe, FoodImage, FoodTile, TopBar, Segmented, Sheet,
});
