// Atoms shared across the Extra Dollar iOS prototype.
// All visual components in one place to reuse across screens.

const ED_FOREST = "#063932";
const ED_FOREST_900 = "#042b25";
const ED_BILL = "#85bb65";
const ED_BILL_700 = "#4d7a39";
const ED_PAPER = "#f7f3f1";
const ED_CREAM = "#eee6e3";
const ED_YELLOW = "#f2dc3b";
const ED_INK = "#1a1a1a";
const ED_FG2 = "#3a3a36";
const ED_FG3 = "#8f8f8f";
const ED_LINE = "rgba(6, 57, 50, 0.10)";

// Danger / negative — single source of truth.
// Source palette: deep brick-red picked for AA contrast on white at 14px+.
const ED_DANGER         = "#a13923";
const ED_DANGER_BG_SUBTLE = "rgba(192, 67, 47, 0.06)";  // light red wash
const ED_DANGER_BG      = "rgba(192, 67, 47, 0.10)";    // chip bg
const ED_DANGER_BORDER  = "rgba(192, 67, 47, 0.18)";    // hairline

// Soft tints used in headers + chips (matched to dollar-bill green).
const ED_BILL_BG_SUBTLE = "rgba(133, 187, 101, 0.12)";
const ED_BILL_BG        = "rgba(133, 187, 101, 0.18)";

// Cream-on-dark text scale (used in dark hero blocks).
const ED_ON_DARK        = "#fff";
const ED_ON_DARK_2      = "rgba(238, 230, 227, 0.78)";
const ED_ON_DARK_3      = "rgba(238, 230, 227, 0.6)";
const ED_ON_DARK_BORDER = "rgba(238, 230, 227, 0.18)";

// Radius scale — six values, each with semantic intent.
// Anything outside this set is a bug or a one-off needing justification.
const ED_R_XS      = 4;    // progress bars, dividers
const ED_R_ICON    = 12;   // small icon containers (≤48px)
const ED_R_BTN     = 14;   // buttons, inputs, search field
const ED_R_SURFACE = 18;   // cards, surfaces, settings groups
const ED_R_HERO    = 24;   // large hero blocks, primary stat tiles
const ED_R_PILL    = 999;  // pills, capsule buttons

// Eyebrow / caps tracking — locked across every uppercase label.
const ED_TRACK_EYEBROW = "0.10em";
const ED_TRACK_CAPS    = "0.12em";  // wider caps (titles, EDStep)

// Animated counter — ticks up to value
function EDCounter({ value, prefix = "$", duration = 900, decimals = 2 }) {
  const [n, setN] = React.useState(0);
  React.useEffect(() => {
    let raf;
    const start = performance.now();
    const from = 0;
    const tick = (t) => {
      const p = Math.min(1, (t - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setN(from + (value - from) * eased);
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [value, duration]);
  return (
    <span style={{ fontFeatureSettings: '"tnum","lnum"', letterSpacing: "-0.02em" }}>
      {prefix}{n.toFixed(decimals)}
    </span>
  );
}

// Stylized abstract card art (color + glyph hint, never the real design)
function EDCardArt({ card, w = 280, h = 176, scale = 1 }) {
  // Scale internals to size — at small sizes, suppress text and shrink glyph.
  const small = w < 110;
  const tiny = w < 90;
  const pad = small ? 8 : 16;
  const issuerSize = small ? 8 : 11;
  const nameSize = small ? 11 : 18;
  const glyphSize = small ? 32 : 56;
  const last4Size = small ? 9 : 13;
  const stripeW = small ? 18 : 28;
  const stripeH = small ? 12 : 20;

  return (
    <div style={{
      width: w, height: h, borderRadius: small ? 10 : 16,
      background: `linear-gradient(135deg, ${card.color} 0%, ${card.color} 60%, ${shade(card.color, -10)} 100%)`,
      position: "relative", overflow: "hidden",
      boxShadow: small ? "0 4px 10px rgba(6, 57, 50, 0.18)" : "0 12px 28px rgba(6, 57, 50, 0.18), 0 2px 6px rgba(6, 57, 50, 0.08)",
      color: card.accent, padding: pad,
      display: "flex", flexDirection: "column", justifyContent: "space-between",
      flexShrink: 0,
      transform: `scale(${scale})`, transformOrigin: "top left",
      boxSizing: "border-box",
    }}>
      {/* abstract glyph mark */}
      <div style={{
        position: "absolute", top: -20, right: -20,
        width: 140, height: 140, borderRadius: "50%",
        background: `radial-gradient(circle at 30% 30%, ${card.accent}26, transparent 70%)`,
      }}/>
      <div style={{ position: "absolute", top: small ? 6 : 18, right: small ? 8 : 18, fontSize: glyphSize, fontWeight: 800, opacity: 0.3, letterSpacing: "-0.04em", lineHeight: 1 }}>{card.glyph}</div>
      <div style={{ display: "flex", flexDirection: "column", gap: 2, position: "relative", maxWidth: "60%" }}>
        <div style={{ fontSize: issuerSize, fontWeight: 600, letterSpacing: "0.12em", textTransform: "uppercase", opacity: 0.82, lineHeight: 1 }}>{card.issuer}</div>
        {!tiny && <div style={{ fontSize: nameSize, fontWeight: 700, letterSpacing: "-0.01em", lineHeight: 1.05, marginTop: 2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{card.short || card.name}</div>}
      </div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", position: "relative" }}>
        <div style={{ display: "flex", gap: 4 }}>
          <div style={{ width: stripeW, height: stripeH, borderRadius: 3, background: card.accent, opacity: 0.85 }}/>
        </div>
        {!tiny && <div style={{ fontSize: last4Size, fontWeight: 600, letterSpacing: small ? "0.10em" : "0.18em", opacity: 0.85, fontFeatureSettings: '"tnum"' }}>•••• {card.last4}</div>}
      </div>
    </div>
  );
}

// Mini card chip (used in lists)
function EDCardChip({ card, size = 36 }) {
  return (
    <div style={{
      width: size, height: size * 0.64, borderRadius: 6, flexShrink: 0,
      background: `linear-gradient(135deg, ${card.color}, ${shade(card.color, -12)})`,
      color: card.accent, position: "relative", overflow: "hidden",
      boxShadow: "0 2px 4px rgba(6,57,50,0.18)",
    }}>
      <div style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", fontSize: size * 0.5, fontWeight: 800, opacity: 0.5 }}>{card.glyph}</div>
    </div>
  );
}

// Format a relative time like "2m ago", "1h ago", "1d ago" — used to normalize
// the mixed time display in NotifRow.
function relTime(value) {
  // Accept either a millisecond timestamp or a number-of-seconds-ago.
  if (!value && value !== 0) return "";
  let s = typeof value === "number" && value > 1e9 ? Math.floor((Date.now() - value) / 1000) : Math.abs(value);
  if (s < 60) return s + "s ago";
  if (s < 3600) return Math.floor(s / 60) + "m ago";
  if (s < 86400) return Math.floor(s / 3600) + "h ago";
  if (s < 86400 * 7) return Math.floor(s / 86400) + "d ago";
  if (s < 86400 * 30) return Math.floor(s / (86400 * 7)) + "w ago";
  return Math.floor(s / (86400 * 30)) + "mo ago";
}

function shade(hex, amt) {
  const c = hex.replace("#", "");
  const r = Math.max(0, Math.min(255, parseInt(c.substring(0,2),16) + amt));
  const g = Math.max(0, Math.min(255, parseInt(c.substring(2,4),16) + amt));
  const b = Math.max(0, Math.min(255, parseInt(c.substring(4,6),16) + amt));
  return "#" + [r,g,b].map(v => v.toString(16).padStart(2,"0")).join("");
}

// "Best card" multiplier badge
function EDBadge({ x, tone = "bill" }) {
  const bg = tone === "bill" ? ED_BILL : ED_FOREST;
  const fg = tone === "bill" ? ED_FOREST_900 : ED_CREAM;
  return (
    <div style={{
      display: "inline-flex", alignItems: "center", justifyContent: "center",
      padding: "3px 9px", borderRadius: 999, background: bg, color: fg,
      fontSize: 12, fontWeight: 800, letterSpacing: "-0.01em",
      fontFeatureSettings: '"tnum"',
    }}>{x}× </div>
  );
}

// Pill (tags / status)
function EDPill({ children, tone = "neutral" }) {
  const styles = {
    neutral: { bg: "rgba(6,57,50,0.06)", fg: ED_FOREST },
    accent: { bg: "rgba(133,187,101,0.18)", fg: ED_BILL_700 },
    warn: { bg: "rgba(242,220,59,0.32)", fg: "#7a5a00" },
    danger: { bg: ED_DANGER_BG, fg: ED_DANGER },
    dark: { bg: ED_FOREST, fg: ED_CREAM },
  }[tone];
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 4,
      padding: "4px 10px", borderRadius: 999,
      background: styles.bg, color: styles.fg,
      fontSize: 11, fontWeight: 700, letterSpacing: "0.04em", textTransform: "uppercase",
    }}>{children}</span>
  );
}

// Eyebrow — uppercase tracking-locked label used across every section.
// Use this instead of inlining the same fontSize/letterSpacing in 12+ places.
function EDEyebrow({ children, color = ED_FG3, style = {} }) {
  return (
    <div style={{
      fontSize: 11, fontWeight: 700, letterSpacing: ED_TRACK_EYEBROW,
      textTransform: "uppercase", color, ...style,
    }}>{children}</div>
  );
}

// Section header (eyebrow + title) — horizontal padding owned by parent (EDBody handles gutters).
function EDSection({ eyebrow, title, action, children, style = {} }) {
  return (
    <section style={{ paddingTop: 24, paddingBottom: 4, ...style }}>
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: title ? 12 : 4 }}>
        <div>
          {eyebrow && <EDEyebrow style={{ marginBottom: 4 }}>{eyebrow}</EDEyebrow>}
          {title && <div style={{ fontSize: 18, fontWeight: 700, letterSpacing: "-0.01em", color: ED_FOREST, lineHeight: 1.2 }}>{title}</div>}
        </div>
        {action}
      </div>
      {children}
    </section>
  );
}

// Card surface
function EDSurface({ children, style = {}, onClick, padded = true }) {
  return (
    <div onClick={onClick} style={{
      background: "#fff", borderRadius: ED_R_SURFACE, border: `1px solid ${ED_LINE}`,
      padding: padded ? 18 : 0, cursor: onClick ? "pointer" : "default",
      transition: "transform 140ms cubic-bezier(0.2,0.7,0.2,1)",
      ...style,
    }}>{children}</div>
  );
}

// Round 36×36 icon button — back / close / bell / avatar.
// Replaces 8+ inline 36×36 buttons across the prototype.
function EDIconButton({ onClick, ariaLabel, variant = "light", badge = false, children, style = {} }) {
  const isDark = variant === "dark";
  const bg = isDark ? "rgba(255,255,255,0.18)" : "rgba(6,57,50,0.06)";
  const fg = isDark ? "#fff" : ED_FOREST;
  return (
    <button onClick={onClick} aria-label={ariaLabel} style={{
      width: 36, height: 36, borderRadius: ED_R_PILL,
      background: bg, color: fg, border: "none",
      cursor: "pointer", display: "inline-flex", alignItems: "center", justifyContent: "center",
      padding: 0, fontFamily: "inherit", position: "relative",
      ...style,
    }}>
      {children}
      {badge && <span style={{
        position: "absolute", top: 7, right: 8, width: 8, height: 8, borderRadius: "50%",
        background: ED_DANGER, border: `2px solid ${isDark ? ED_FOREST_900 : ED_PAPER}`,
      }}/>}
    </button>
  );
}

// Standard back-chevron button — light or dark variant.
function EDBackButton({ onClick, variant = "light" }) {
  return (
    <EDIconButton onClick={onClick} ariaLabel="Back" variant={variant}>
      <svg width="9" height="16" viewBox="0 0 9 16" fill="none">
        <path d="M7.5 1.5L1.5 8l6 6.5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    </EDIconButton>
  );
}

// Small inline pill button — trailing actions, "Use →", "Copy", "Mark all read".
// Replaces ~8 inline pill buttons across screens.
function EDPillButton({ onClick, tone = "forest", size = "md", children, style = {} }) {
  const palette = {
    forest:  { bg: ED_FOREST, fg: ED_CREAM },
    bill:    { bg: ED_BILL, fg: ED_FOREST_900 },
    ghost:   { bg: "transparent", fg: ED_BILL_700 },
    onDark:  { bg: "rgba(238,230,227,0.10)", fg: ED_CREAM },
  }[tone];
  const sizing = {
    sm: { height: 30, padding: "0 12px", fontSize: 12 },
    md: { height: 36, padding: "0 14px", fontSize: 13 },
    lg: { height: 42, padding: "0 18px", fontSize: 14 },
  }[size];
  return (
    <button onClick={onClick} style={{
      background: palette.bg, color: palette.fg, border: "none",
      borderRadius: ED_R_PILL, fontWeight: 700, cursor: "pointer",
      fontFamily: "inherit", whiteSpace: "nowrap",
      display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6,
      ...sizing, ...style,
    }}>{children}</button>
  );
}

// Tab bar
function EDTabBar({ active, onChange }) {
  const tabs = [
    { id: "home", label: "Home", icon: "house" },
    { id: "which", label: "Which", icon: "search" },
    { id: "insights", label: "Insights", icon: "chart" },
    { id: "cards", label: "Cards", icon: "stack" },
    { id: "profile", label: "Profile", icon: "person" },
  ];
  return (
    <div style={{
      position: "absolute", bottom: 0, left: 0, right: 0, zIndex: 40,
      paddingBottom: 28, paddingTop: 8,
      background: "linear-gradient(to top, rgba(247,243,241,0.96) 60%, rgba(247,243,241,0))",
      backdropFilter: "blur(12px)", WebkitBackdropFilter: "blur(12px)",
    }}>
      <div style={{
        display: "flex", justifyContent: "space-around", alignItems: "center",
        padding: "0 12px",
      }}>
        {tabs.map(t => (
          <button key={t.id} onClick={() => onChange(t.id)} style={{
            background: "none", border: "none", padding: "8px 12px",
            display: "flex", flexDirection: "column", alignItems: "center", gap: 4,
            color: active === t.id ? ED_FOREST : ED_FG3,
            cursor: "pointer", flex: 1,
          }}>
            <EDTabIcon name={t.icon} active={active === t.id} />
            <div style={{ fontSize: 10, fontWeight: active === t.id ? 700 : 500, letterSpacing: "-0.01em" }}>{t.label}</div>
          </button>
        ))}
      </div>
    </div>
  );
}

function EDTabIcon({ name, active }) {
  const stroke = active ? ED_FOREST : ED_FG3;
  const fill = active ? ED_FOREST : "none";
  const sw = 1.8;
  if (name === "house") return (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none">
      <path d="M3 11l9-7 9 7v9a2 2 0 01-2 2h-4v-7h-6v7H5a2 2 0 01-2-2v-9z" stroke={stroke} strokeWidth={sw} strokeLinejoin="round" fill={active ? fill : "none"} fillOpacity="0.08"/>
    </svg>
  );
  if (name === "search") return (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none">
      <circle cx="11" cy="11" r="7" stroke={stroke} strokeWidth={sw}/>
      <path d="M16.5 16.5L21 21" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </svg>
  );
  if (name === "chart") return (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none">
      <path d="M4 20V10M10 20V4M16 20v-7M22 20H2" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </svg>
  );
  if (name === "stack") return (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none">
      <rect x="3" y="6" width="18" height="12" rx="2" stroke={stroke} strokeWidth={sw}/>
      <path d="M3 11h18" stroke={stroke} strokeWidth={sw}/>
    </svg>
  );
  if (name === "person") return (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none">
      <circle cx="12" cy="8" r="4" stroke={stroke} strokeWidth={sw}/>
      <path d="M4 21c0-4 4-7 8-7s8 3 8 7" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </svg>
  );
}

// Sparkline
function EDSpark({ data, w = 80, h = 28, color = ED_BILL }) {
  const max = Math.max(...data);
  const min = Math.min(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => `${(i/(data.length-1))*w},${h - ((v-min)/range)*h*0.9 - h*0.05}`).join(" ");
  return (
    <svg width={w} height={h}>
      <polyline points={pts} fill="none" stroke={color} strokeWidth={2} strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

Object.assign(window, {
  // Color tokens
  ED_FOREST, ED_FOREST_900, ED_BILL, ED_BILL_700, ED_PAPER, ED_CREAM, ED_YELLOW,
  ED_INK, ED_FG2, ED_FG3, ED_LINE,
  ED_DANGER, ED_DANGER_BG_SUBTLE, ED_DANGER_BG, ED_DANGER_BORDER,
  ED_BILL_BG_SUBTLE, ED_BILL_BG,
  ED_ON_DARK, ED_ON_DARK_2, ED_ON_DARK_3, ED_ON_DARK_BORDER,
  // Radius scale
  ED_R_XS, ED_R_ICON, ED_R_BTN, ED_R_SURFACE, ED_R_HERO, ED_R_PILL,
  // Tracking
  ED_TRACK_EYEBROW, ED_TRACK_CAPS,
  // Components
  EDCounter, EDCardArt, EDCardChip, EDBadge, EDPill,
  EDEyebrow, EDSection, EDSurface,
  EDIconButton, EDBackButton, EDPillButton,
  EDTabBar, EDSpark, shade, relTime,
});
