// components.jsx — Shared primitives for the SuSu Funding Dashboard.
// All exports are attached to window at the bottom so other Babel scripts can use them.

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

// ── Icons (lightweight SVG, no library) ─────────────────────────────────────
const Icon = ({ d, size = 16, stroke = 1.6, fill = "none", className = "" }) => (
  <svg className={className} width={size} height={size} viewBox="0 0 24 24" fill={fill}
       stroke="currentColor" strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round">
    {Array.isArray(d) ? d.map((p, i) => <path key={i} d={p} />) : <path d={d} />}
  </svg>
);

const Icons = {
  home:        "M3 11.5 12 4l9 7.5V20a1 1 0 0 1-1 1h-5v-6h-6v6H4a1 1 0 0 1-1-1z",
  search:      ["M11 19a8 8 0 1 1 0-16 8 8 0 0 1 0 16Z", "m21 21-4.3-4.3"],
  bell:        ["M6 8a6 6 0 1 1 12 0c0 7 3 9 3 9H3s3-2 3-9Z","M10 21a2 2 0 0 0 4 0"],
  briefcase:   ["M3 9a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z","M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"],
  map:         ["M4 6.5 10 4l6 2.5L20 4v13.5L14 20l-6-2.5L4 20z","M10 4v16","M16 6.5V20"],
  layers:      ["m12 3 9 5-9 5-9-5z","m3 13 9 5 9-5","m3 18 9 5 9-5"],
  users:       ["M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2","M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8","M22 21v-2a4 4 0 0 0-3-3.87","M16 3.13a4 4 0 0 1 0 7.75"],
  user:        ["M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2","M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8"],
  building:    ["M3 21h18","M5 21V7l8-4v18","M19 21V11l-6-4","M9 9v.01","M9 13v.01","M9 17v.01","M14 13v.01","M14 17v.01"],
  arrowRight:  "M5 12h14M13 5l7 7-7 7",
  arrowUpRight:["M7 17 17 7","M7 7h10v10"],
  external:    ["M15 3h6v6","M10 14 21 3","M21 14v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5"],
  calendar:    ["M3 6a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z","M3 10h18","M8 2v4","M16 2v4"],
  clock:       ["M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Z","M12 7v5l3 2"],
  filter:      "M3 5h18l-7 9v6l-4-2v-4z",
  chevronDown: "m6 9 6 6 6-6",
  check:       "m5 12 5 5L20 7",
  plus:        "M12 5v14M5 12h14",
  globe:       ["M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Z","M3 12h18","M12 3a14 14 0 0 1 0 18 14 14 0 0 1 0-18Z"],
  spark:       "M12 3v4M12 17v4M3 12h4M17 12h4M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M5.6 18.4l2.8-2.8M15.6 8.4l2.8-2.8",
  flame:       "M12 2s5 4 5 9a5 5 0 0 1-10 0c0-3 2-3 2-6 2 2 3 3 3 3z",
  bookmark:    "M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z",
  trending:    ["m3 17 6-6 4 4 8-8","M14 7h7v7"],
  shield:      "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",
  zap:         "M13 2 3 14h7l-1 8 10-12h-7z",
  scale:       ["M16 16c0 2-1.5 4-4 4s-4-2-4-4","M12 3v17","M8 7l4-4 4 4","M6 10 3 13l3 3","M18 10l3 3-3 3"],
  leaf:        "M11 20A7 7 0 0 1 4 13c0-4 3-9 9-11 0 4-3 7-3 11s3 7 7 7-3-1-6-1z",
  x:           "M6 6l12 12M6 18 18 6",
  send:        "m22 2-11 11M22 2l-7 20-4-9-9-4z",
  link:        ["M10 13a5 5 0 0 0 7.07 0l3-3a5 5 0 1 0-7.07-7.07l-1.5 1.5","M14 11a5 5 0 0 0-7.07 0l-3 3a5 5 0 1 0 7.07 7.07L12.5 19.5"],
  dot:         "M12 12.01",
  more:        "M5 12.01M12 12.01M19 12.01",
  star:        "m12 2 3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01z",
  flag:        ["M4 22V4","M4 4h12l-2 4 2 4H4"],
  pipeline:    ["M3 5h18","M3 12h12","M3 19h6"],
  doc:         ["M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z","M14 3v6h6"],
  euro:        "M18 7a5 5 0 1 0 0 10M3 10h11M3 14h11",
  dollar:      "M12 2v20M17 5H10a3 3 0 0 0 0 6h4a3 3 0 0 1 0 6H7",
  grid:        ["M3 3h8v8H3z","M13 3h8v8h-8z","M3 13h8v8H3z","M13 13h8v8h-8z"],
  list:        ["M8 6h13","M8 12h13","M8 18h13","M3 6h.01","M3 12h.01","M3 18h.01"],
};

// ── KPI Card ────────────────────────────────────────────────────────────────
function Kpi({ label, value, delta, deltaTone = "success", icon, sparkData }) {
  const deltaCls = {
    success: { color: "var(--success)" },
    danger:  { color: "var(--danger)"  },
    info:    { color: "var(--info)"    },
    mute:    { color: "var(--text-mute)" },
  }[deltaTone] || {};

  return (
    <div className="kpi fade-in">
      <div className="row gap-8" style={{ color: "var(--text-mute)" }}>
        <div className="kpi-label">{label}</div>
      </div>
      {sparkData && <Sparkline data={sparkData} className="kpi-spark" />}
      <div className="kpi-val">{value}</div>
      {delta && <div className="kpi-delta" style={deltaCls}>{delta}</div>}
    </div>
  );
}

// Tiny inline sparkline
function Sparkline({ data, width = 80, height = 32, className = "" }) {
  const max = Math.max(...data), min = Math.min(...data);
  const range = (max - min) || 1;
  const step = width / (data.length - 1);
  const pts = data.map((v, i) => `${(i * step).toFixed(1)},${(height - ((v - min) / range) * (height - 4) - 2).toFixed(1)}`).join(" ");
  return (
    <svg className={className} width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
      <defs>
        <linearGradient id={`sg-${className}`} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%"  stopColor="var(--accent)" stopOpacity=".5" />
          <stop offset="100%" stopColor="var(--accent)" stopOpacity="0" />
        </linearGradient>
      </defs>
      <polyline points={pts} fill="none" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
      <polygon points={`0,${height} ${pts} ${width},${height}`} fill={`url(#sg-${className})`} />
    </svg>
  );
}

// ── Match score ring ────────────────────────────────────────────────────────
function MatchRing({ score, size = 40, stroke = 4 }) {
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const dash = (score / 100) * c;
  const tone = score >= 85 ? "var(--success)" : score >= 70 ? "var(--accent)" : score >= 55 ? "var(--warning)" : "var(--danger)";
  return (
    <div className="match-ring" style={{ width: size, height: size }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        <circle cx={size/2} cy={size/2} r={r} stroke="var(--surface-3)" strokeWidth={stroke} fill="none" />
        <circle cx={size/2} cy={size/2} r={r} stroke={tone} strokeWidth={stroke} fill="none"
                strokeDasharray={`${dash} ${c - dash}`} strokeLinecap="round" />
        <text x={size/2} y={size/2 + 4} textAnchor="middle">{score}</text>
      </svg>
    </div>
  );
}

// ── Pill / badge ────────────────────────────────────────────────────────────
function Pill({ tone, dot, children, style }) {
  const cls = "pill" + (tone ? ` pill-${tone}` : "");
  return <span className={cls} style={style}>{dot && <span className="dot" />}{children}</span>;
}

// Map a region → tone
function regionTone(region) {
  return ({ EU: "info", USA: "purple", Asia: "teal", Africa: "accent", Multilateral: "success" })[region] || "info";
}
function typeTone(t) {
  if (/grant/i.test(t))   return "accent";
  if (/loan/i.test(t))    return "info";
  if (/equity/i.test(t))  return "purple";
  if (/convert/i.test(t)) return "teal";
  return "info";
}

// ── Format helpers ──────────────────────────────────────────────────────────
function fmtAmount(min, max, currency = "USD") {
  const sym = currency === "EUR" ? "€" : currency === "GBP" ? "£" : "$";
  const fmt = (n) => n >= 1_000_000 ? `${(n / 1_000_000).toFixed(n % 1_000_000 ? 1 : 0)}M`
                    : n >= 1_000     ? `${(n / 1_000).toFixed(0)}K`
                    : `${n}`;
  if (min === max) return `${sym}${fmt(max)}`;
  if (!min) return `up to ${sym}${fmt(max)}`;
  return `${sym}${fmt(min)} – ${sym}${fmt(max)}`;
}

function fmtDeadline(o) {
  if (o.deadline === "rolling") return { label: "Rolling", urgency: "mute" };
  const days = o.daysLeft;
  if (days < 0)  return { label: `Closed ${-days}d ago`, urgency: "danger" };
  if (days <= 14) return { label: `${days}d left`, urgency: "danger" };
  if (days <= 45) return { label: `${days}d left`, urgency: "warning" };
  return { label: `${days}d left`, urgency: "mute" };
}

// ── Mini opp card (for list / pipeline) ────────────────────────────────────
function OppRow({ opp, onClick }) {
  const dl = fmtDeadline(opp);
  return (
    <div className="opp-card" onClick={onClick}>
      <div className="opp-flag">{opp.flag}</div>
      <div className="stack gap-6" style={{minWidth:0}}>
        <div className="row gap-10" style={{flexWrap:"wrap"}}>
          <div style={{fontWeight:600,fontSize:14.5,letterSpacing:"-.01em",lineHeight:1.25}}>{opp.name}</div>
          <Pill tone={regionTone(opp.region)} dot>{opp.region}</Pill>
          <Pill tone={typeTone(opp.type)}>{opp.type}</Pill>
          {opp.consortium && <Pill tone="purple">Consortium</Pill>}
        </div>
        <div className="row gap-10 dim" style={{fontSize:12.5}}>
          <span>{opp.source}</span>
          <span style={{color:"var(--text-faint)"}}>·</span>
          <span className="opp-amount">{fmtAmount(opp.amountMin, opp.amountMax, opp.currency)}</span>
          <span style={{color:"var(--text-faint)"}}>·</span>
          <span style={{color: `var(--${dl.urgency === "mute" ? "text-mute" : dl.urgency})`}}>
            {dl.label}
          </span>
        </div>
      </div>
      <div className="match">
        <MatchRing score={opp.match} />
        <div className="stack gap-4">
          <div style={{fontSize:11,letterSpacing:".08em",textTransform:"uppercase",color:"var(--text-mute)",fontWeight:600}}>Match</div>
          <div style={{fontSize:12,color:"var(--text-dim)"}}>fit score</div>
        </div>
      </div>
    </div>
  );
}

// ── Drawer ──────────────────────────────────────────────────────────────────
function Drawer({ open, onClose, children }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => e.key === "Escape" && onClose();
    document.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => { document.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
  }, [open, onClose]);
  if (!open) return null;
  return (
    <React.Fragment>
      <div className="drawer-scrim" onClick={onClose} />
      <div className="drawer">{children}</div>
    </React.Fragment>
  );
}

// ── Section header ──────────────────────────────────────────────────────────
function SectionHead({ title, kicker, right }) {
  return (
    <div className="row between" style={{marginBottom:14}}>
      <div className="stack gap-4">
        <h2 className="h-section">{title}</h2>
        {kicker && <div className="h-kicker">{kicker}</div>}
      </div>
      {right}
    </div>
  );
}

// Export to window so other Babel scripts can pick them up
Object.assign(window, {
  Icon, Icons, Kpi, Sparkline, MatchRing, Pill, Drawer, SectionHead, OppRow,
  fmtAmount, fmtDeadline, regionTone, typeTone,
});
