// dash-atoms.jsx — shared primitives for the BTC Now dashboard

const DASH_GRADIENT = 'linear-gradient(135deg, #FFD60A 0%, #FF9F0A 50%, #FF453A 100%)';
const DASH_MONO = "'JetBrains Mono', ui-monospace, monospace";
const DASH_DISPLAY = "'Clash Display', 'Inter', sans-serif";

// ═══ MOCK DATA (whale persona) ════════════════════════════════════════════
const MOCK = {
  firstName: 'Marc',
  lastName: 'Dumpff',
  cashUsd: 248_412.50,
  btc: 5.8423,
  btcPriceSeed: 68_412.40,
  fico: 812,
  monthlyIncome: 42_000,
  fromIncome: 118_000,  // portion of credit from FICO/income
  transactions: [
    { id: 't1', merchant: 'Nobu · Malibu',            cat: 'Dining',    amt: -412.80,  sats: 412, when: 'Today · 8:14pm' },
    { id: 't2', merchant: 'Shell',                    cat: 'Fuel',      amt: -84.20,   sats: 84,  when: 'Today · 11:02am' },
    { id: 't3', merchant: 'Apple Store',              cat: 'Tech',      amt: -2_399.00,sats: 2399,when: 'Yesterday' },
    { id: 't4', merchant: 'Velocity Black · Yacht',   cat: 'Travel',    amt: -18_400.00,sats:18400,when: 'Apr 21' },
    { id: 't5', merchant: 'Whole Foods',              cat: 'Groceries', amt: -312.45,  sats: 312, when: 'Apr 20' },
    { id: 't6', merchant: 'Delta · LAX → JFK',        cat: 'Travel',    amt: -1_840.00,sats: 1840,when: 'Apr 19' },
    { id: 't7', merchant: 'Blue Bottle Coffee',       cat: 'Dining',    amt: -8.75,    sats: 9,   when: 'Apr 19' },
    { id: 't8', merchant: 'Equinox',                  cat: 'Fitness',   amt: -325.00,  sats: 325, when: 'Apr 18' },
  ],
};

// ═══ FORMATTERS ════════════════════════════════════════════════════════════
function fmtUsd(n, opts = {}) {
  const { decimals = 2, abbreviate = false } = opts;
  if (abbreviate && Math.abs(n) >= 1000) {
    if (Math.abs(n) >= 1_000_000) return `$${(n/1_000_000).toFixed(2)}M`;
    if (Math.abs(n) >= 1000) return `$${(n/1000).toFixed(1)}k`;
  }
  const neg = n < 0;
  const abs = Math.abs(n);
  return (neg ? '-' : '') + '$' + abs.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
}
function fmtBtc(n) {
  return '₿' + n.toLocaleString('en-US', { minimumFractionDigits: 4, maximumFractionDigits: 4 });
}
function fmtSats(n) {
  return n.toLocaleString('en-US') + ' sats';
}

// ═══ ANIMATED NUMBER ══════════════════════════════════════════════════════
// Smoothly interpolates between value changes
function AnimatedNumber({ value, format, duration = 500, style }) {
  const [display, setDisplay] = React.useState(value);
  const rafRef = React.useRef(null);
  const startRef = React.useRef(null);
  const fromRef = React.useRef(value);

  React.useEffect(() => {
    cancelAnimationFrame(rafRef.current);
    fromRef.current = display;
    startRef.current = null;
    const animate = (t) => {
      if (startRef.current == null) startRef.current = t;
      const progress = Math.min(1, (t - startRef.current) / duration);
      const eased = 1 - Math.pow(1 - progress, 3);
      const next = fromRef.current + (value - fromRef.current) * eased;
      setDisplay(next);
      if (progress < 1) rafRef.current = requestAnimationFrame(animate);
    };
    rafRef.current = requestAnimationFrame(animate);
    return () => cancelAnimationFrame(rafRef.current);
  }, [value]);

  return <span style={style}>{format(display)}</span>;
}

// ═══ BTC PRICE TICKER HOOK ════════════════════════════════════════════════
// Pulls live price from CoinGecko's free public API every 30s,
// with small simulated drift between polls so the UI feels live.
// Falls back to simulated drift only if the network call fails.
function useBtcPrice(seed = 68_412.40) {
  const [price, setPrice] = React.useState(seed);
  const [source, setSource] = React.useState('loading'); // 'live' | 'offline' | 'loading'
  const basePriceRef = React.useRef(seed);

  // Poll CoinGecko every 30s
  React.useEffect(() => {
    let cancelled = false;
    const fetchPrice = async () => {
      try {
        const res = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd', { cache: 'no-store' });
        if (!res.ok) throw new Error('HTTP ' + res.status);
        const data = await res.json();
        const p = data?.bitcoin?.usd;
        if (!cancelled && typeof p === 'number' && p > 0) {
          basePriceRef.current = p;
          setPrice(p);
          setSource('live');
        }
      } catch (e) {
        if (!cancelled) setSource(prev => prev === 'live' ? 'live' : 'offline');
      }
    };
    fetchPrice();
    const id = setInterval(fetchPrice, 30_000);
    return () => { cancelled = true; clearInterval(id); };
  }, []);

  // Between polls, drift small amounts around the real base price so the
  // animated number and credit limit feel alive.
  React.useEffect(() => {
    const id = setInterval(() => {
      setPrice(p => {
        const base = basePriceRef.current;
        const drift = (Math.random() - 0.5) * (base * 0.0008); // ±0.08%
        // pull gently back toward base
        const pull = (base - p) * 0.08;
        return p + drift + pull;
      });
    }, 1600);
    return () => clearInterval(id);
  }, []);

  return price;
}

// ═══ SCREEN SHELL for dashboard tabs ══════════════════════════════════════
// Outer div is the positioning context (non-scrolling), inner div scrolls.
// This ensures modals with position:absolute;inset:0 align to the viewport,
// not to the scrolled content.
function DashScreen({ children, modals, scroll = true, padTop = 56, padBottom = 90 }) {
  return (
    <div style={{
      width: '100%', height: '100%',
      background: '#050507',
      backgroundImage: 'radial-gradient(ellipse 100% 40% at 50% 0%, rgba(255,159,10,0.06) 0%, transparent 60%)',
      color: '#F5F5F7',
      position: 'relative',
      overflow: 'hidden',
    }}>
      <div style={{
        width: '100%', height: '100%',
        overflowY: scroll ? 'auto' : 'hidden',
        overflowX: 'hidden',
        boxSizing: 'border-box',
        paddingTop: padTop, paddingBottom: padBottom,
      }}>
        {children}
      </div>
      {/* Modals render outside the scroll container so they align to the viewport */}
      {modals}
    </div>
  );
}

// ═══ TAB BAR (bottom nav) ═════════════════════════════════════════════════
function TabBar({ active, onChange }) {
  const tabs = [
    { id: 'home',      label: 'Home',      icon: (
      <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12 12 3l9 9"/><path d="M5 10v10h14V10"/></svg>
    )},
    { id: 'card',      label: 'Card',      icon: (
      <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg>
    )},
    { id: 'invest',    label: 'Invest',    icon: (
      <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 17l6-6 4 4 8-8"/><path d="M14 7h7v7"/></svg>
    )},
    { id: 'loans',     label: 'Loans',     icon: (
      <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="4" y="6" width="16" height="12" rx="2"/><circle cx="12" cy="12" r="2.5"/><path d="M7 12h.01M17 12h.01"/></svg>
    )},
    { id: 'concierge', label: 'Concierge', icon: (
      <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>
    )},
  ];
  return (
    <div style={{
      position: 'absolute', bottom: 0, left: 0, right: 0,
      height: 82, paddingBottom: 20,
      background: 'linear-gradient(180deg, rgba(5,5,7,0) 0%, rgba(5,5,7,0.85) 40%, rgba(5,5,7,0.98) 100%)',
      backdropFilter: 'blur(24px)',
      WebkitBackdropFilter: 'blur(24px)',
      borderTop: '1px solid rgba(255,255,255,0.06)',
      display: 'flex', alignItems: 'flex-end', justifyContent: 'space-around',
      zIndex: 20,
    }}>
      {tabs.map(t => {
        const isActive = t.id === active;
        return (
          <button key={t.id} onClick={() => onChange(t.id)} style={{
            flex: 1, background: 'transparent', border: 'none',
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2,
            padding: '8px 4px', cursor: 'pointer',
            color: isActive ? '#FF9F0A' : 'rgba(245,245,247,0.45)',
            fontFamily: "'Inter', sans-serif",
            fontSize: 10, fontWeight: 500, letterSpacing: '-0.01em',
            transition: 'color 0.2s',
            position: 'relative',
          }}>
            {isActive && (
              <div style={{
                position: 'absolute', top: 0, left: '50%', transform: 'translateX(-50%)',
                width: 22, height: 2, borderRadius: 2, background: DASH_GRADIENT,
                boxShadow: '0 0 10px rgba(255,159,10,0.6)',
              }}/>
            )}
            {t.icon}
            <span>{t.label}</span>
          </button>
        );
      })}
    </div>
  );
}

// ═══ DASH CARD (surface/panel) ════════════════════════════════════════════
function DashCard({ children, style = {}, glow = false, onClick }) {
  return (
    <div onClick={onClick} style={{
      background: 'linear-gradient(180deg, rgba(20,20,26,0.7) 0%, rgba(10,10,14,0.85) 100%)',
      border: '1px solid rgba(255,255,255,0.06)',
      borderRadius: 20,
      boxShadow: glow
        ? '0 0 40px rgba(255,159,10,0.15), inset 0 1px 0 rgba(255,255,255,0.06)'
        : 'inset 0 1px 0 rgba(255,255,255,0.04)',
      padding: 16,
      cursor: onClick ? 'pointer' : 'default',
      transition: 'all 0.2s',
      ...style,
    }}>{children}</div>
  );
}

// ═══ HEADER (scrolls with content) ═══════════════════════════════════════
function DashHeader({ title, subtitle, right }) {
  return (
    <div style={{
      padding: '8px 20px 12px',
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
    }}>
      <div style={{ minWidth: 0 }}>
        {subtitle && (
          <div style={{
            fontFamily: DASH_MONO, fontSize: 10, letterSpacing: '0.15em',
            color: 'rgba(245,245,247,0.45)', textTransform: 'uppercase',
            marginBottom: 2,
          }}>{subtitle}</div>
        )}
        <div style={{
          fontFamily: DASH_DISPLAY, fontSize: 22, fontWeight: 600,
          letterSpacing: '-0.03em', color: '#fff',
        }}>{title}</div>
      </div>
      {right}
    </div>
  );
}

// ═══ SPARKLINE ═══════════════════════════════════════════════════════════
function Sparkline({ data, width = 80, height = 28, color = '#FF9F0A', fill = true }) {
  const min = Math.min(...data);
  const max = Math.max(...data);
  const range = max - min || 1;
  const points = data.map((v, i) => {
    const x = (i / (data.length - 1)) * width;
    const y = height - ((v - min) / range) * height;
    return `${x},${y}`;
  }).join(' ');
  const fillPath = `M 0,${height} L ${points.replace(/ /g, ' L ')} L ${width},${height} Z`;
  return (
    <svg width={width} height={height} style={{ overflow: 'visible' }}>
      <defs>
        <linearGradient id={`sp-${color.replace('#','')}`} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.4"/>
          <stop offset="100%" stopColor={color} stopOpacity="0"/>
        </linearGradient>
      </defs>
      {fill && <path d={fillPath} fill={`url(#sp-${color.replace('#','')})`}/>}
      <polyline points={points} fill="none" stroke={color} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

// ═══ SAT BADGE ═══════════════════════════════════════════════════════════
function SatBadge({ sats }) {
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      padding: '3px 8px', borderRadius: 100,
      background: 'rgba(255,159,10,0.1)',
      border: '1px solid rgba(255,159,10,0.25)',
      color: '#FF9F0A',
      fontFamily: DASH_MONO, fontSize: 10, fontWeight: 600,
      letterSpacing: '0.02em',
    }}>
      +{sats.toLocaleString()} sats
    </div>
  );
}

Object.assign(window, {
  MOCK, DASH_GRADIENT, DASH_MONO, DASH_DISPLAY,
  fmtUsd, fmtBtc, fmtSats, AnimatedNumber, useBtcPrice,
  DashScreen, TabBar, DashCard, DashHeader, Sparkline, SatBadge,
});
