/* ============================================================
   B4IOU — shared UI primitives + icons
   ============================================================ */
const { useState, useRef, useEffect, useCallback, useMemo } = React;

/* ---- tiny stroke icons (geometric only) ---- */
const Ico = {
  arrow: (p) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" {...p}><path d="M5 12h14M13 6l6 6-6 6" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  back: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" {...p}><path d="M19 12H5M11 18l-6-6 6-6" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  check: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" {...p}><path d="M5 12.5l4.5 4.5L19 6.5" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  lock: (p) => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" {...p}><rect x="4.5" y="10.5" width="15" height="10" rx="2.4" stroke="currentColor" strokeWidth="2"/><path d="M8 10.5V8a4 4 0 018 0v2.5" stroke="currentColor" strokeWidth="2"/></svg>,
  search: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" {...p}><circle cx="11" cy="11" r="6.5" stroke="currentColor" strokeWidth="2.2"/><path d="M16 16l4.5 4.5" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/></svg>,
  upload: (p) => <svg width="26" height="26" viewBox="0 0 24 24" fill="none" {...p}><path d="M12 16V4M7 9l5-5 5 5" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/><path d="M4 16v2.5A1.5 1.5 0 005.5 20h13a1.5 1.5 0 001.5-1.5V16" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/></svg>,
  doc: (p) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" {...p}><path d="M7 3h7l4 4v14a1 1 0 01-1 1H7a1 1 0 01-1-1V4a1 1 0 011-1z" stroke="currentColor" strokeWidth="2"/><path d="M14 3v4h4M9 13h6M9 17h6" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/></svg>,
  download: (p) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" {...p}><path d="M12 4v11M8 11l4 4 4-4" stroke="currentColor" strokeWidth="2.3" strokeLinecap="round" strokeLinejoin="round"/><path d="M5 19h14" stroke="currentColor" strokeWidth="2.3" strokeLinecap="round"/></svg>,
  share: (p) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" {...p}><circle cx="6" cy="12" r="2.6" stroke="currentColor" strokeWidth="2"/><circle cx="18" cy="6" r="2.6" stroke="currentColor" strokeWidth="2"/><circle cx="18" cy="18" r="2.6" stroke="currentColor" strokeWidth="2"/><path d="M8.3 10.8l7.4-3.6M8.3 13.2l7.4 3.6" stroke="currentColor" strokeWidth="2"/></svg>,
  copy: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" {...p}><rect x="8" y="8" width="12" height="12" rx="2.2" stroke="currentColor" strokeWidth="2"/><path d="M16 8V5.5A1.5 1.5 0 0014.5 4h-9A1.5 1.5 0 004 5.5v9A1.5 1.5 0 005.5 16H8" stroke="currentColor" strokeWidth="2"/></svg>,
  flag: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" {...p}><path d="M6 21V4M6 4h11l-2 4 2 4H6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  bolt: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" {...p}><path d="M13 2L4 14h7l-1 8 9-12h-7l1-8z" stroke="currentColor" strokeWidth="2" strokeLinejoin="round"/></svg>,
  shield: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" {...p}><path d="M12 3l7 3v5c0 5-3.5 8-7 10-3.5-2-7-5-7-10V6l7-3z" stroke="currentColor" strokeWidth="2" strokeLinejoin="round"/></svg>,
  mail: (p) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" {...p}><rect x="3" y="5" width="18" height="14" rx="2" stroke="currentColor" strokeWidth="2"/><path d="M4 7l8 6 8-6" stroke="currentColor" strokeWidth="2"/></svg>,
  spark: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" {...p}><path d="M12 3v6M12 15v6M3 12h6M15 12h6" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/></svg>,
  x: (p) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" {...p}><path d="M6 6l12 12M18 6L6 18" stroke="currentColor" strokeWidth="2.3" strokeLinecap="round"/></svg>,
};

function Brand({ pct, onHome }) {
  return (
    <div className="brand" onClick={onHome}>
      <span className="mark">B4</span>
      <span>B4<span className="pct">IOU</span></span>
    </div>
  );
}

function TopBar({ step, totalSteps, label, onHome }) {
  const pct = Math.round((step / totalSteps) * 100);
  return (
    <div className="topbar">
      <div className="topbar-row">
        <Brand onHome={onHome} />
        <span className="step-tag">{label}</span>
      </div>
      <div className="progress"><i style={{ width: `${Math.max(6, pct)}%` }} /></div>
    </div>
  );
}

function Btn({ kind = "accent", size = "lg", arrow, children, ...rest }) {
  return (
    <button className={`btn btn-${kind} btn-${size}`} {...rest}>
      {children}
      {arrow && <span className="arrow"><Ico.arrow /></span>}
    </button>
  );
}

function BackBtn({ onClick, label = "Back" }) {
  return <button className="linkbtn" onClick={onClick}><Ico.back /> {label}</button>;
}

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

/* searchable combobox with free typing */
function Combo({ label, value, onChange, placeholder, options }) {
  const [open, setOpen] = useState(false);
  const [active, setActive] = useState(-1);
  const ref = useRef(null);
  const exactMatch = useMemo(() => {
    const q = (value || "").toLowerCase().trim();
    return !!q && options.some((o) => o.name.toLowerCase() === q);
  }, [value, options]);
  const filtered = useMemo(() => {
    const q = (value || "").toLowerCase().trim();
    // empty OR an already-picked value → show the full list so the user can re-browse
    if (!q || exactMatch) return options.slice(0, 60);
    return options.filter(o => o.name.toLowerCase().includes(q)).slice(0, 60);
  }, [value, options, exactMatch]);

  useEffect(() => {
    function onDoc(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, []);

  // raise the containing card above sibling cards so the dropdown isn't clipped
  useEffect(() => {
    const card = ref.current && ref.current.closest(".card");
    if (card) card.classList.toggle("card-raised", open);
    return () => { if (card) card.classList.remove("card-raised"); };
  }, [open]);

  const total = options.length;
  const matches = filtered.length;
  const noun = /program|degree|major/i.test(label || "") ? "program" : "school";

  return (
    <div className="field combo" ref={ref}>
      {label && <label>{label}</label>}
      <div style={{ position: "relative" }}>
        <input
          className="input"
          value={value}
          placeholder={placeholder}
          onChange={(e) => { onChange(e.target.value); setOpen(true); setActive(-1); }}
          onFocus={(e) => { setOpen(true); if (exactMatch) e.target.select(); }}
          onClick={() => setOpen(true)}
          style={{ paddingRight: 42 }}
        />
        <span style={{ position: "absolute", right: 15, top: "50%", transform: "translateY(-50%)", color: "var(--text-3)" }}><Ico.search /></span>
      </div>
      {open && (filtered.length > 0 || (value || "").trim()) && (
        <div className="combo-menu">
          <div className="combo-head">
            <span>{(value || "").trim() && !exactMatch ? `${matches} match${matches === 1 ? "" : "es"}` : `${total} ${noun}s · scroll`}</span>
            <span className="combo-head-hint"><Ico.search /> Type your own</span>
          </div>
          <div className="combo-scroll">
            {filtered.map((o, i) => (
              <div
                key={o.name}
                className={`combo-item ${i === active ? "active" : ""}`}
                onMouseDown={() => { onChange(o.name); setOpen(false); }}
              >
                <span>{o.name}</span>
                {o.meta && <span className="meta">{o.meta}</span>}
              </div>
            ))}
            {filtered.length === 0 && (
              <div className="combo-empty">No match in our quick-pick list — your typed name works just fine.</div>
            )}
          </div>
          {(value || "").trim() && !exactMatch && (
            <div className="combo-free" onMouseDown={() => setOpen(false)}>
              <span>Use “{value.trim()}”</span>
              <span className="meta">↵ runs any {noun}</span>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

function Field({ label, ...rest }) {
  return (
    <div className="field">
      {label && <label>{label}</label>}
      <input className="input" {...rest} />
    </div>
  );
}

function Toast({ msg }) {
  if (!msg) return null;
  return <div className="toast">{msg}</div>;
}

function fmt(n) {
  if (n === null || n === undefined || isNaN(n)) return "—";
  return "$" + Math.round(n).toLocaleString("en-US");
}

Object.assign(window, { useState, useRef, useEffect, useCallback, useMemo, Ico, Brand, TopBar, Btn, BackBtn, Pill, Combo, Field, Toast, fmt });
