/* shared.jsx — icons, tiny utilities, common components */

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

// ─── Icons (lucide-style minimal stroke set, ~14-18px)
const Icon = ({ d, size = 14, strokeWidth = 1.75, fill = "none", className = "icon", style }) => (
  <svg className={className} width={size} height={size} viewBox="0 0 24 24"
    fill={fill} stroke="currentColor" strokeWidth={strokeWidth}
    strokeLinecap="round" strokeLinejoin="round" style={style}>
    {Array.isArray(d) ? d.map((p, i) => <path key={i} d={p} />) : <path d={d} />}
  </svg>
);

const Icons = {
  activity:    "M22 12h-4l-3 9-6-18-3 9H2",
  upload:      ["M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", "M17 8l-5-5-5 5", "M12 3v12"],
  download:    ["M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", "M7 10l5 5 5-5", "M12 15V3"],
  table:       ["M3 3h18v18H3z", "M3 9h18", "M3 15h18", "M9 3v18", "M15 3v18"],
  events:      ["M22 12h-4l-3 9-6-18-3 9H2"],
  sources:     ["M3 6h18", "M7 12h10", "M11 18h2"],
  chart:       ["M3 3v18h18", "M7 14l4-4 3 3 5-6"],
  recap:       ["M3 3h18v6H3z", "M3 13h18v8H3z", "M7 17h6"],
  settings:    ["M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z", "M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"],
  search:      ["M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z", "m21 21-4.3-4.3"],
  filter:      "M22 3H2l8 9.5V19l4 2v-8.5L22 3z",
  eye:         ["M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z", "M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"],
  eyeOff:      ["M9.9 4.2A10 10 0 0 1 12 4c7 0 10 7 10 7a16 16 0 0 1-2.4 3.3", "M6.6 6.6A16 16 0 0 0 2 11s3 7 10 7c1.7 0 3.2-.4 4.6-1", "M14.1 14.1a3 3 0 1 1-4.2-4.2", "m2 2 20 20"],
  arrowUp:     ["M12 19V5", "m5 12 7-7 7 7"],
  arrowDown:   ["M12 5v14", "m19 12-7 7-7-7"],
  arrowUpRight: ["M7 17l10-10", "M7 7h10v10"],
  expand:      ["M3 3h6v6H3z", "M21 21h-6v-6h6z"],
  chevDown:    "m6 9 6 6 6-6",
  chevRight:   "m9 18 6-6-6-6",
  close:       ["m18 6-12 12", "m6 6 12 12"],
  trash:       ["M3 6h18", "M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2", "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6", "M10 11v6", "M14 11v6"],
  edit:        ["M12 20h9", "M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"],
  plus:        ["M12 5v14", "M5 12h14"],
  minus:       ["M5 12h14"],
  dots:        ["M12 5h.01", "M12 12h.01", "M12 19h.01"],
  hash:        ["M4 9h16", "M4 15h16", "M10 3 8 21", "M16 3l-2 18"],
  zap:         "M13 2 3 14h9l-1 8 10-12h-9l1-8z",
  shield:      ["M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"],
  database:    ["M12 8c4.97 0 9-1.34 9-3s-4.03-3-9-3-9 1.34-9 3 4.03 3 9 3z", "M3 5v6c0 1.66 4.03 3 9 3s9-1.34 9-3V5", "M3 11v6c0 1.66 4.03 3 9 3s9-1.34 9-3v-6"],
  server:      ["M3 4h18v6H3z", "M3 14h18v6H3z", "M7 7h.01", "M7 17h.01"],
  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 8z"],
  link:        ["M10 13a5 5 0 0 0 7.5.5l3-3a5 5 0 0 0-7-7l-1.7 1.7", "M14 11a5 5 0 0 0-7.5-.5l-3 3a5 5 0 0 0 7 7l1.7-1.7"],
  refresh:     ["M21 12a9 9 0 0 1-15 6.7L3 16", "M3 12a9 9 0 0 1 15-6.7L21 8", "M21 3v5h-5", "M3 21v-5h5"],
  alert:       ["M12 9v4", "M12 17h.01", "M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"],
  spark:       "m13 2-3 7h4l-3 7", // small lightning
  trend:       ["m3 17 6-6 4 4 8-8", "M14 7h7v7"],
  trendDown:   ["m3 7 6 6 4-4 8 8", "M14 17h7v-7"],
  clock:       ["M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z", "M12 6v6l4 2"],
  message:     ["M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"],
  brain:       ["M12 5a3 3 0 1 0-5.5-1.6", "M12 5a3 3 0 1 1 5.5-1.6", "M12 5v14", "M6.5 8a3 3 0 1 0-2 5", "M17.5 8a3 3 0 1 1 2 5", "M8 17a3 3 0 1 0-2 4", "M16 17a3 3 0 1 1 2 4"],
  check:       "m5 12 5 5L20 7",
  sliders:     ["M4 21v-7", "M4 10V3", "M12 21v-9", "M12 8V3", "M20 21v-5", "M20 12V3", "M1 14h6", "M9 8h6", "M17 16h6"],
  sun:         ["M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10z","M12 1v2","M12 21v2","M4.22 4.22l1.42 1.42","M18.36 18.36l1.42 1.42","M1 12h2","M21 12h2","M4.22 19.78l1.42-1.42","M18.36 5.64l1.42-1.42"],
  moon:        "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z",
  monitor:     ["M2 4h20v14H2z","M8 22h8","M12 18v4"],
  logout:      ["M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4", "M16 17l5-5-5-5", "M21 12H9"],
  menu:        ["M4 6h16", "M4 12h16", "M4 18h16"],
  lock:        ["M5 11h14a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1z", "M8 11V7a4 4 0 0 1 8 0v4"],
};

const I = (name, props={}) => <Icon d={Icons[name]} {...props} />;

// ─── Tiny helpers
const cx = (...xs) => xs.filter(Boolean).join(" ");
const _toDate = (d) => d instanceof Date ? d : new Date(d);
const fmtTime = (d, opts={}) => {
  const date = _toDate(d);
  return date.toLocaleString("en-US", { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
};
const fmtTimeOnly = (d) => _toDate(d).toLocaleString("en-US", { hour: "numeric", minute: "2-digit" });
const fmtDay = (d) => _toDate(d).toLocaleString("en-US", { month: "short", day: "numeric" });
const fmtNum = (n, dec=2) => n == null ? "—" : Number(n).toFixed(dec);
const fmtCurrency = (n) => n == null ? "—" : (n < 0 ? "-" : "") + "$" + Math.abs(n).toFixed(2);
const fmtPct = (n) => n == null ? "—" : (n >= 0 ? "+" : "") + (n*100).toFixed(1) + "%";

// ─── Status pill (live / idle / error)
function StatusPill({ status="ready" }) {
  return (
    <span className="status">
      <span className="dot"></span>
      {status}
    </span>
  );
}

// ─── Pill (action / confidence)
function ActionPill({ kind }) {
  const k = (kind || "").toLowerCase();
  return <span className={cx("pill", k)}>{k}</span>;
}
function ConfPill({ level }) {
  const l = (level || "").toLowerCase();
  return <span className={cx("pill", l)}>{l}</span>;
}

// ─── Analyst chip
function AnalystChip({ analyst, analysts }) {
  const a = analysts.find(x => x.handle === analyst);
  const col = a?.color || "var(--accent)";
  return (
    <span className="analyst">
      <span className="swatch" style={{ "--col": col }} />
      {analyst}
    </span>
  );
}

// ─── Instrument helpers (shares vs options)
const isOption = (x) => x ? (x.instrument ? x.instrument === "option" : !!x.contract) : false;

// Builds a contract label from structured fields, falling back to the stored string.
function contractText(x) {
  if (x.contract) return x.contract;
  const parts = [];
  if (x.expiry) parts.push(x.expiry);
  if (x.strike != null) parts.push(`${x.strike}${x.optionType === "put" ? "P" : x.optionType === "call" ? "C" : ""}`);
  return parts.join(" ");
}

// Cell that cleanly distinguishes options from shares.
function InstrumentCell({ event }) {
  if (!isOption(event)) {
    return <span className="inst"><span className="inst-tag shares">SHARES</span></span>;
  }
  const detail = contractText(event);
  const kind = event.optionType === "put" ? "put" : event.optionType === "call" ? "call" : "opt";
  const tag = kind === "put" ? "PUT" : kind === "call" ? "CALL" : "OPT";
  return (
    <span className="inst">
      <span className={cx("inst-tag", kind)}>{tag}</span>
      {detail && <span className="inst-detail">{detail}</span>}
    </span>
  );
}

// Segmented All / Options / Shares filter.
function InstrumentFilter({ value, onChange }) {
  const opts = [["all", "All"], ["option", "Options"], ["shares", "Shares"]];
  return (
    <div className="seg">
      {opts.map(([v, l]) => (
        <button key={v} className={cx("seg-btn", value === v && "on")} onClick={() => onChange(v)}>{l}</button>
      ))}
    </div>
  );
}
function matchesInstrument(x, filter) {
  if (filter === "all") return true;
  return filter === "option" ? isOption(x) : !isOption(x);
}

// ─── Empty state
function Empty({ msg }) { return <div className="empty">{msg}</div>; }

// API base — same-origin in prod, localhost:3001 in dev
function apiBase() {
  if (typeof window === "undefined") return "";
  const { hostname, origin } = window.location;
  if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "") {
    return "http://localhost:3001";
  }
  return origin;
}

// All API calls go through this so the session cookie is always sent.
function tapeFetch(url, opts = {}) {
  return fetch(url, { credentials: "include", ...opts });
}

// Export to window so other babel scripts can use them
Object.assign(window, {
  Icon, I, Icons, cx, fmtTime, fmtTimeOnly, fmtDay, fmtNum, fmtCurrency, fmtPct,
  StatusPill, ActionPill, ConfPill, AnalystChip, Empty,
  isOption, contractText, InstrumentCell, InstrumentFilter, matchesInstrument,
  useState, useEffect, useMemo, useRef, useCallback, Fragment,
  apiBase, tapeFetch,
});
