// Shared UI primitives — shadcn-flavoured.
// All Babel scripts share global scope after window.assign at bottom.

const { useState, useEffect, useRef, useMemo, useCallback, Fragment } = React;
const Ic = window.Icons;

// ─── Button ───
const Button = ({ variant = "outline", size = "", icon: Icon, children, ...rest }) => (
  <button {...rest} className={`btn btn-${variant} ${size ? "btn-" + size : ""} ${rest.className || ""}`}>
    {Icon ? <Icon size={size === "xs" ? 12 : size === "sm" ? 14 : 15} /> : null}
    {children}
  </button>
);
const IconButton = ({ variant = "outline", size = "sm", icon: Icon, ...rest }) => (
  <button {...rest} className={`btn btn-${variant} btn-icon btn-${size} ${rest.className || ""}`}>
    <Icon size={size === "xs" ? 12 : 15} />
  </button>
);

// ─── Card ───
const Card = ({ className = "", children, ...rest }) => (
  <div {...rest} className={`card ${className}`}>{children}</div>
);
const CardHead = ({ title, desc, action }) => (
  <div className="card-head">
    <div className="head-text">
      {title && <div className="card-title">{title}</div>}
      {desc && <div className="card-desc">{desc}</div>}
    </div>
    {action}
  </div>
);

// ─── KPI tile ───
const Kpi = ({ label, value, unit, delta, deltaDir = "up", icon: Icon, accent = "" }) => (
  <Card className="kpi">
    <div className="kpi-label">
      {Icon ? <Icon size={14} /> : null}
      {label}
    </div>
    <div className="kpi-value">{value}{unit && <small>{unit}</small>}</div>
    {delta != null && (
      <div className={`kpi-delta ${deltaDir}`}>
        {deltaDir === "up" ? <Ic.ArrowUp size={12}/> : <Ic.ArrowDown size={12}/>}
        {delta}
      </div>
    )}
  </Card>
);

// ─── Badge ───
const Badge = ({ tone = "outline", icon: Icon, children }) => (
  <span className={`badge badge-${tone}`}>
    {Icon ? <Icon size={11}/> : null}
    {children}
  </span>
);
const StatusDot = ({ tone = "success", pulse = false }) => (
  <span className={`dot ${tone} ${pulse ? "pulse" : ""}`} />
);
const StatusBadge = ({ status }) => {
  const map = {
    // ── canonical status tokens (§3.2) ──
    pending:       ["pending","Pending"],
    "in-progress": ["in-progress","In progress"],
    approved:      ["approved","Approved"],
    rejected:      ["rejected","Rejected"],
    closed:        ["closed","Closed"],
    // ── domain statuses (map onto the canonical palette) ──
    open:        ["info","Open"],
    broadcasted: ["info","Broadcasted"],
    receiving:   ["in-progress","Receiving responses"],
    confirmed:   ["approved","Confirmed"],
    fulfilled:   ["avocado","Fulfilled"],
    cancelled:   ["closed","Cancelled"],
    shortlist:   ["pulp","Shortlisting"],
    awarded:     ["approved","Awarded"],
    "in-delivery": ["pending","In delivery"],
    draft:       ["outline","Draft"],
    scheduled:   ["info","Scheduled"],
    production:  ["pulp","In production"],
    dispatched:  ["approved","Dispatched"],
    running:     ["pulp","Running"],
    complete:    ["approved","Complete"],
    pass:        ["approved","Pass"],
    hold:        ["pending","Hold"],
    reject:      ["rejected","Reject"],
    review:      ["pending","Review"],
    declined:    ["closed","Declined"],
    active:      ["approved","Active"],
    invited:     ["outline","Invited"],
    ok:          ["approved","Healthy"],
    low:         ["pending","Low"],
    critical:    ["rejected","Critical"],
    high:        ["pending","High"],
    overdue:     ["rejected","Overdue"],
    due:         ["pending","Due today"],
  };
  const [tone, label] = map[status] || ["outline", status];
  return <Badge tone={tone}>{label}</Badge>;
};

// ── Severity badge (§3.2 severity palette) ──
const SEVERITY_MAP = {
  low:      ["sev-low", "Low"],
  medium:   ["sev-medium", "Medium"],
  high:     ["sev-high", "High"],
  critical: ["sev-critical", "Critical"],
};
const SeverityBadge = ({ level }) => {
  const [tone, label] = SEVERITY_MAP[level] || ["outline", level];
  return <Badge tone={tone}>{label}</Badge>;
};

// ── Journey badge (§3.2 journey palette — lead lifecycle) ──
const JOURNEY_MAP = {
  aware:                ["jrn-aware", "Aware"],
  committee:            ["jrn-committee", "Committed"],
  planted:              ["jrn-planted", "Planted"],
  growing:              ["jrn-growing", "Growing"],
  "first-harvest":      ["jrn-first-harvest", "First harvest"],
  "procurement-active": ["jrn-procurement-active", "Procurement active"],
};
const JourneyBadge = ({ stage }) => {
  const [tone, label] = JOURNEY_MAP[stage] || ["outline", stage];
  return <Badge tone={tone}>{label}</Badge>;
};

// ─── Avatar ───
const Avatar = ({ initials, tone, size = "" }) => {
  const tones = ["soil","avocado","pulp"];
  const t = tone || tones[(initials?.charCodeAt(0) || 0) % 3];
  return <span className={`avatar avatar-${t} ${size ? "avatar-" + size : ""}`}>{initials}</span>;
};

// ─── Tabs ───
const Tabs = ({ value, onChange, options }) => (
  <div className="tabs-group">
    <div className="tabs">
      {options.map(o => (
        <button key={o.value} className={value === o.value ? "active" : ""} onClick={()=> onChange(o.value)}>
          {o.label}{o.count != null && <span style={{opacity:0.6, marginLeft:6}}>({o.count})</span>}
        </button>
      ))}
    </div>
    <select className="tabs-select" value={value} onChange={(e)=> onChange(e.target.value)}>
      {options.map(o => (
        <option key={o.value} value={o.value}>
          {o.label}{o.count != null ? ` (${o.count})` : ""}
        </option>
      ))}
    </select>
  </div>
);

// ─── Progress ───
const Progress = ({ value, max = 100, tone = "" }) => (
  <div className={`progress ${tone}`}>
    <div style={{ width: Math.max(0, Math.min(100, (value / max) * 100)) + "%" }} />
  </div>
);

// ─── Switch ───
const Switch = ({ checked, onChange }) => (
  <div className={`switch ${checked ? "on" : ""}`} onClick={()=> onChange?.(!checked)} role="switch" aria-checked={checked} tabIndex={0} />
);

// ─── Drawer ───
const Drawer = ({ open, onClose, title, sub, footer, children, wide = false }) => {
  if (!open) return null;
  return (
    <div className="drawer-overlay" onClick={(e)=> { if (e.target === e.currentTarget) onClose?.(); }}>
      <aside className={`drawer ${wide ? "wide" : ""}`}>
        <div className="drawer-head">
          <div>
            <div style={{fontSize:16, fontWeight:600, letterSpacing:"-0.01em"}}>{title}</div>
            {sub && <div className="muted" style={{fontSize:12.5, marginTop:2}}>{sub}</div>}
          </div>
          <IconButton variant="ghost" icon={Ic.X} onClick={onClose} />
        </div>
        <div className="drawer-body">{children}</div>
        {footer && <div className="drawer-foot">{footer}</div>}
      </aside>
    </div>
  );
};

// ─── Modal ───
const Modal = ({ open, onClose, title, sub, footer, wide = false, children }) => {
  if (!open) return null;
  return (
    <div className="modal-overlay" onClick={(e)=> { if (e.target === e.currentTarget) onClose?.(); }}>
      <div className={`modal ${wide ? "wide" : ""}`}>
        <div className="drawer-head">
          <div>
            <div style={{fontSize:16, fontWeight:600, letterSpacing:"-0.01em"}}>{title}</div>
            {sub && <div className="muted" style={{fontSize:12.5, marginTop:2}}>{sub}</div>}
          </div>
          <IconButton variant="ghost" icon={Ic.X} onClick={onClose} />
        </div>
        <div className="drawer-body">{children}</div>
        {footer && <div className="drawer-foot">{footer}</div>}
      </div>
    </div>
  );
};

// ─── Sparkline (SVG line) ───
const Sparkline = ({ data, height = 48, color = "var(--cat-1)", fill = "var(--seq-1)" }) => {
  if (!data || !data.length) return null;
  const w = 140, h = height;
  const min = Math.min(...data), max = Math.max(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => [
    (i / (data.length - 1)) * w,
    h - ((v - min) / range) * (h - 6) - 3
  ]);
  const path = pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + "," + p[1].toFixed(1)).join(" ");
  const area = `${path} L${w},${h} L0,${h} Z`;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" height={h} preserveAspectRatio="none">
      <path d={area} fill={fill} opacity="0.5"/>
      <path d={path} fill="none" stroke={color} strokeWidth="1.75"/>
    </svg>
  );
};

// ─── Bar chart (vertical, simple) ───
const BarChart = ({ data, labels, height = 160, color = "var(--cat-1)" }) => {
  const max = Math.max(...data);
  return (
    <div>
      <div style={{display:"flex", alignItems:"flex-end", gap:6, height}}>
        {data.map((v, i) => (
          <div key={i} style={{flex:1, display:"flex", flexDirection:"column", alignItems:"center", gap:4, height:"100%"}}>
            <div style={{flex:1, width:"100%", display:"flex", alignItems:"flex-end"}}>
              <div style={{
                width:"100%",
                height: ((v / max) * 100) + "%",
                background: color,
                borderRadius: "3px 3px 0 0",
                transition: "height 0.4s"
              }}/>
            </div>
          </div>
        ))}
      </div>
      {labels && (
        <div style={{display:"flex", gap:6, marginTop:6}}>
          {labels.map((l, i) => (
            <div key={i} style={{flex:1, textAlign:"center", fontSize:10.5, color:"var(--muted-foreground)"}}>{l}</div>
          ))}
        </div>
      )}
    </div>
  );
};

// ─── Donut ───
const Donut = ({ value, max = 100, size = 80, stroke = 10, color = "var(--cat-1)", label }) => {
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const pct = Math.max(0, Math.min(1, value / max));
  return (
    <div style={{display:"inline-flex", flexDirection:"column", alignItems:"center", gap:6}}>
      <svg width={size} height={size}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--muted)" strokeWidth={stroke}/>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={color} strokeWidth={stroke}
                strokeLinecap="round"
                strokeDasharray={`${c * pct} ${c}`}
                transform={`rotate(-90 ${size/2} ${size/2})`}/>
        <text x={size/2} y={size/2 + 5} textAnchor="middle" fontSize="16" fontWeight="600">{Math.round(value)}{max === 100 ? "%" : ""}</text>
      </svg>
      {label && <div style={{fontSize:11.5, color:"var(--muted-foreground)"}}>{label}</div>}
    </div>
  );
};

// ─── Toast ───
const ToastCtx = React.createContext(null);
const ToastProvider = ({ children }) => {
  const [toasts, setToasts] = useState([]);
  const push = useCallback((toast) => {
    const id = Math.random().toString(36).slice(2);
    setToasts(ts => [...ts, { id, ...toast }]);
    setTimeout(() => setToasts(ts => ts.filter(t => t.id !== id)), toast.duration || 3000);
  }, []);
  return (
    <ToastCtx.Provider value={push}>
      {children}
      <div className="toast-wrap">
        {toasts.map(t => (
          <div key={t.id} className={`toast ${t.tone || ""}`}>
            <span className="toast-icon">
              {t.tone === "danger" ? <Ic.Warning size={16}/> : <Ic.CheckCircle size={16}/>}
            </span>
            <div className="toast-body">
              <div className="toast-title">{t.title}</div>
              {t.desc && <div className="toast-desc">{t.desc}</div>}
            </div>
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
};
const useToast = () => React.useContext(ToastCtx);

// ─── Empty state ───
const Empty = ({ icon: Icon = Ic.Box, title, desc, action }) => (
  <div style={{padding:"40px 20px", textAlign:"center", display:"flex", flexDirection:"column", alignItems:"center", gap:8}}>
    <div style={{width:48, height:48, borderRadius:12, background:"var(--muted)", display:"inline-flex", alignItems:"center", justifyContent:"center", color:"var(--muted-foreground)"}}>
      <Icon size={22}/>
    </div>
    <div style={{fontSize:14, fontWeight:600}}>{title}</div>
    {desc && <div className="muted" style={{fontSize:12.5, maxWidth:320}}>{desc}</div>}
    {action && <div style={{marginTop:6}}>{action}</div>}
  </div>
);

Object.assign(window, {
  Button, IconButton, Card, CardHead, Kpi, Badge, StatusDot, StatusBadge,
  SeverityBadge, JourneyBadge,
  Avatar, Tabs, Progress, Switch, Drawer, Modal,
  Sparkline, BarChart, Donut,
  ToastProvider, useToast, Empty,
});
