/* global React, I, generateRevenueSeries */
// note: no top-level destructure — use React.useX directly
var { useState, useEffect, useRef, useMemo } = React;

function fmtMoney(v) {
  if (v >= 1000) return '$' + (v/1000).toFixed(v >= 10000 ? 1 : 2).replace(/\.0$/, '') + 'k';
  return '$' + v;
}
function fmtMoneyFull(v) { return '$' + v.toLocaleString('en-US'); }
function fmtDate(d) {
  return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
}

/* ============ Welcome row ============ */
function WelcomeRow() {
  const today = new Date(2026, 3, 19);
  const dateStr = today.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' });
  return (
    <div className="welcome">
      <div>
        <h1>Good morning, Andy <span style={{ display:'inline-block', transform:'translateY(-1px)' }}>👋</span></h1>
        <div className="date">{dateStr} · Here's what's happening today.</div>
      </div>
      <div className="actions">
        <button className="btn btn-ghost"><I.download/> Export CSV</button>
        <button className="btn btn-primary"><I.plus/> New</button>
      </div>
    </div>
  );
}

/* ============ KPI ============ */
function KpiCard({ kpi, loading }) {
  const up = kpi.trend >= 0;
  const toneColor = { purple: '#A78BFA', green: '#34D399', red: '#F87171', amber: '#FBBF24' }[kpi.tone];
  const Icn = kpi.icon;

  if (loading) {
    return (
      <div className="card kpi">
        <div className="kpi-head">
          <div className="skeleton sk-icon"/>
          <div className="skeleton sk-label"/>
        </div>
        <div className="skeleton sk-value"/>
        <div className="kpi-foot">
          <div className="skeleton sk-trend"/>
          <div className="skeleton sk-spark"/>
        </div>
      </div>
    );
  }

  return (
    <div className="card kpi" onMouseMove={e => {
      const r = e.currentTarget.getBoundingClientRect();
      e.currentTarget.style.setProperty('--mx', ((e.clientX - r.left) / r.width * 100) + '%');
      e.currentTarget.style.setProperty('--my', ((e.clientY - r.top) / r.height * 100) + '%');
    }}>
      <div className="kpi-head">
        <div className={`kpi-icon ${kpi.tone === 'green' ? 'green' : kpi.tone === 'red' ? 'red' : kpi.tone === 'amber' ? 'amber' : ''}`}>
          <Icn/>
        </div>
        <div className="kpi-label">{kpi.label}</div>
      </div>
      <div className="kpi-value"><AnimatedNumber value={kpi.raw} format={kpi.key === 'rev' ? 'money' : kpi.key === 'aov' ? 'money-s' : kpi.key === 'cnv' ? 'pct' : 'num'}/></div>
      <div className="kpi-foot">
        <span className={`trend ${up ? 'up' : 'down'}`}>
          {up ? <I.arrowUp/> : <I.arrowDown/>}
          {Math.abs(kpi.trend).toFixed(1)}%
          <span className="period">vs last month</span>
        </span>
        <Sparkline data={kpi.spark} color={toneColor}/>
      </div>
    </div>
  );
}

function AnimatedNumber({ value, format = 'num', dur = 900 }) {
  const [v, setV] = useState(0);
  useEffect(() => {
    const start = performance.now();
    let raf;
    const tick = (now) => {
      const t = Math.min(1, (now - start) / dur);
      const eased = 1 - Math.pow(1 - t, 3);
      setV(value * eased);
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [value]);
  let out;
  if (format === 'money') out = '$' + Math.round(v).toLocaleString();
  else if (format === 'money-s') out = '$' + Math.round(v).toLocaleString();
  else if (format === 'pct') out = v.toFixed(1) + '%';
  else out = Math.round(v).toLocaleString();
  return out;
}

function KpiRow({ loading }) {
  return (
    <div className="kpis">
      {DATA.kpis.map(k => <KpiCard key={k.key} kpi={k} loading={loading}/>)}
    </div>
  );
}

/* ============ Revenue Line Chart ============ */
function RevenueChart() {
  const [range, setRange] = useState('30d');
  const days = { '7d': 7, '30d': 30, '90d': 90, '1y': 365 }[range];
  const series = useMemo(() => generateRevenueSeries(days, range === '7d' ? 3 : range === '30d' ? 7 : range === '90d' ? 11 : 17), [range]);
  const [hover, setHover] = useState(null);
  const [animKey, setAnimKey] = useState(0);
  useEffect(() => { setAnimKey(k => k + 1); }, [range]);

  const wrapRef = useRef(null);
  const [size, setSize] = useState({ w: 800, h: 280 });
  useEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const ro = new ResizeObserver(entries => {
      const r = entries[0].contentRect;
      setSize({ w: r.width, h: r.height });
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  const { w, h } = size;
  const padL = 44, padR = 16, padT = 16, padB = 28;
  const innerW = Math.max(10, w - padL - padR);
  const innerH = Math.max(10, h - padT - padB);
  const min = Math.min(...series.map(p => p.value));
  const max = Math.max(...series.map(p => p.value));
  const yMin = Math.floor(min / 5000) * 5000;
  const yMax = Math.ceil(max / 5000) * 5000;
  const yRange = yMax - yMin || 1;

  const pts = series.map((p, i) => {
    const x = padL + (i / (series.length - 1)) * innerW;
    const y = padT + (1 - (p.value - yMin) / yRange) * innerH;
    return { x, y, ...p };
  });

  // smooth path using catmull-rom -> bezier
  function smoothPath(points) {
    if (points.length < 2) return '';
    let d = `M${points[0].x},${points[0].y}`;
    for (let i = 0; i < points.length - 1; i++) {
      const p0 = points[i - 1] || points[i];
      const p1 = points[i];
      const p2 = points[i + 1];
      const p3 = points[i + 2] || p2;
      const cp1x = p1.x + (p2.x - p0.x) / 6;
      const cp1y = p1.y + (p2.y - p0.y) / 6;
      const cp2x = p2.x - (p3.x - p1.x) / 6;
      const cp2y = p2.y - (p3.y - p1.y) / 6;
      d += ` C${cp1x},${cp1y} ${cp2x},${cp2y} ${p2.x},${p2.y}`;
    }
    return d;
  }
  const linePath = smoothPath(pts);
  const areaPath = linePath + ` L${pts[pts.length-1].x},${padT + innerH} L${pts[0].x},${padT + innerH} Z`;

  // y ticks
  const yTicks = 4;
  const yLabels = Array.from({ length: yTicks + 1 }, (_, i) => yMin + (yRange * i) / yTicks);

  // x ticks
  const xTickCount = range === '7d' ? 7 : range === '30d' ? 6 : range === '90d' ? 6 : 6;
  const xTickIdx = Array.from({ length: xTickCount }, (_, i) => Math.round((i / (xTickCount - 1)) * (series.length - 1)));

  const onMove = (e) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const x = e.clientX - rect.left;
    // find closest point
    let best = 0, bestD = Infinity;
    for (let i = 0; i < pts.length; i++) {
      const d = Math.abs(pts[i].x - x);
      if (d < bestD) { bestD = d; best = i; }
    }
    setHover({ i: best });
  };

  const latestVal = series[series.length - 1].value;
  const firstVal = series[0].value;
  const delta = ((latestVal - firstVal) / firstVal) * 100;
  const total = series.reduce((a, p) => a + p.value, 0);

  const gid = 'rev-fill';
  const lid = 'rev-line';

  return (
    <div className="card chart-card">
      <div className="chart-head">
        <div>
          <h3 className="chart-title">Revenue</h3>
          <div className="chart-sub">Daily revenue over the selected window</div>
          <div className="chart-meta">
            <span className="big">{fmtMoneyFull(total)}</span>
            <span className={`trend ${delta >= 0 ? 'up' : 'down'}`}>
              {delta >= 0 ? <I.arrowUp/> : <I.arrowDown/>}{Math.abs(delta).toFixed(1)}%
            </span>
          </div>
        </div>
        <div className="seg">
          {['7d','30d','90d','1y'].map(r => (
            <button key={r} className={range === r ? 'active' : ''} onClick={() => setRange(r)}>
              {r === '1y' ? '1y' : r}
            </button>
          ))}
        </div>
      </div>

      <div className="chart-wrap" ref={wrapRef} onMouseMove={onMove} onMouseLeave={() => setHover(null)}>
        <svg width={w} height={h} style={{ display: 'block', overflow: 'visible' }}>
          <defs>
            <linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor="#A78BFA" stopOpacity="0.42"/>
              <stop offset="55%" stopColor="#7C3AED" stopOpacity="0.14"/>
              <stop offset="100%" stopColor="#7C3AED" stopOpacity="0"/>
            </linearGradient>
            <linearGradient id={lid} x1="0" y1="0" x2="1" y2="0">
              <stop offset="0%" stopColor="#A78BFA"/>
              <stop offset="100%" stopColor="#7C3AED"/>
            </linearGradient>
            <clipPath id="clip-rev"><rect x={padL} y={padT} width={innerW} height={innerH}/></clipPath>
          </defs>

          {/* gridlines */}
          {yLabels.map((lv, i) => {
            const y = padT + (1 - (lv - yMin) / yRange) * innerH;
            return (
              <g key={i}>
                <line x1={padL} x2={padL + innerW} y1={y} y2={y} stroke="#232B42" strokeDasharray="3 4"/>
                <text x={padL - 10} y={y + 3} fill="#6B7387" fontSize="10.5" textAnchor="end">
                  {fmtMoney(lv)}
                </text>
              </g>
            );
          })}
          {/* x labels */}
          {xTickIdx.map((idx, i) => {
            const p = pts[idx];
            const d = series[idx].date;
            const label = range === '1y'
              ? d.toLocaleDateString('en-US', { month: 'short' })
              : d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
            return <text key={i} x={p.x} y={padT + innerH + 18} fill="#6B7387" fontSize="10.5" textAnchor="middle">{label}</text>;
          })}

          {/* area */}
          <g clipPath="url(#clip-rev)">
            <path key={`area-${animKey}`} d={areaPath} fill={`url(#${gid})`}
                  style={{ opacity: 0, animation: 'fadeIn 800ms ease 300ms forwards' }}/>
            <path key={`line-${animKey}`} d={linePath} fill="none" stroke={`url(#${lid})`} strokeWidth="2.2" strokeLinejoin="round" strokeLinecap="round"
                  style={{
                    strokeDasharray: 3000,
                    strokeDashoffset: 3000,
                    animation: 'drawLine 1100ms cubic-bezier(.2,.7,.2,1) forwards',
                  }}/>
          </g>

          {/* hover */}
          {hover && (
            <g>
              <line x1={pts[hover.i].x} x2={pts[hover.i].x} y1={padT} y2={padT + innerH} stroke="#A78BFA" strokeOpacity="0.35" strokeDasharray="3 3"/>
              <circle cx={pts[hover.i].x} cy={pts[hover.i].y} r="8" fill="#7C3AED" fillOpacity="0.18"/>
              <circle cx={pts[hover.i].x} cy={pts[hover.i].y} r="4" fill="#fff" stroke="#7C3AED" strokeWidth="2"/>
            </g>
          )}
        </svg>

        {hover && (
          <div className="tooltip" style={{
            left: Math.min(Math.max(48, pts[hover.i].x), w - 120),
            top: pts[hover.i].y,
          }}>
            <div className="tt-date">{fmtDate(series[hover.i].date)}</div>
            <div className="tt-val"><span className="dot"/>{fmtMoneyFull(series[hover.i].value)}</div>
          </div>
        )}
      </div>
      <style>{`
        @keyframes drawLine { to { stroke-dashoffset: 0; } }
        @keyframes fadeIn { to { opacity: 1; } }
      `}</style>
    </div>
  );
}

/* ============ Top Products ============ */
function TopProducts() {
  const [animated, setAnimated] = useState(false);
  useEffect(() => {
    const t = setTimeout(() => setAnimated(true), 200);
    return () => clearTimeout(t);
  }, []);
  return (
    <div className="card panel">
      <div className="panel-head">
        <h3 className="panel-title">Top products</h3>
        <button className="link-btn">View all</button>
      </div>
      <div className="tp-list">
        {DATA.products.map((p, i) => (
          <div key={p.name} className="tp-row">
            <div className="tp-ico">{p.icon}</div>
            <div className="tp-body">
              <div className="tp-name">{p.name} <span className="tp-sub"> · {p.sub} · {p.units}</span></div>
              <div className="tp-bar">
                <div className="tp-fill" style={{ width: animated ? `${p.pct}%` : '0%', transitionDelay: `${i * 80}ms` }}/>
              </div>
            </div>
            <div className="tp-pct">{p.pct}%</div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ============ Activity Feed ============ */
function ActivityFeed() {
  return (
    <div className="card panel">
      <div className="panel-head">
        <h3 className="panel-title">Recent activity</h3>
        <button className="link-btn">See all</button>
      </div>
      <div className="feed">
        {DATA.activity.map((a, i) => (
          <div key={i} className="feed-item">
            <div className="avatar md" style={{ background: `linear-gradient(135deg, ${a.grad[0]}, ${a.grad[1]})` }}>{a.init}</div>
            <div className="feed-text">
              <b>{a.who}</b> <span className="action">{a.action}</span> <b>{a.obj}</b>
            </div>
            <div className="feed-time">{a.time}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ============ Orders Table ============ */
function OrdersTable() {
  const [sortCol, setSortCol] = useState('id');
  const [sortDir, setSortDir] = useState('desc');
  const [page, setPage] = useState(1);

  const pageSize = 10;
  const totalRows = 247;
  const totalPages = Math.ceil(totalRows / pageSize);

  const sorted = useMemo(() => {
    const rows = [...DATA.orders];
    rows.sort((a, b) => {
      let av = a[sortCol], bv = b[sortCol];
      if (sortCol === 'amount') { av = a.amount; bv = b.amount; }
      if (sortCol === 'cust') { av = a.cust; bv = b.cust; }
      if (typeof av === 'string') return sortDir === 'asc' ? av.localeCompare(bv) : bv.localeCompare(av);
      return sortDir === 'asc' ? av - bv : bv - av;
    });
    return rows;
  }, [sortCol, sortDir]);

  const toggleSort = (col) => {
    if (sortCol === col) setSortDir(d => d === 'asc' ? 'desc' : 'asc');
    else { setSortCol(col); setSortDir('desc'); }
  };

  const SortIco = ({ col }) => {
    if (sortCol !== col) return <span className="sort-ico"><I.sort/></span>;
    return <span className="sort-ico">{sortDir === 'asc' ? <I.sortUp/> : <I.sortDown/>}</span>;
  };

  const STATUS = {
    ok:   { label: 'Completed', cls: 'ok' },
    wait: { label: 'Pending',   cls: 'wait' },
    err:  { label: 'Refunded',  cls: 'err' },
  };

  const start = (page - 1) * pageSize + 1;
  const end = Math.min(page * pageSize, totalRows);

  return (
    <div className="card table-card">
      <div className="table-head-bar">
        <div>
          <h3 className="panel-title">Recent orders</h3>
          <div className="chart-sub" style={{ marginTop: 2 }}>Latest transactions across all channels</div>
        </div>
        <div className="table-filters">
          <button className="chip-filter"><I.filter/> All statuses <I.chevDown/></button>
          <button className="chip-filter">Last 7 days <I.chevDown/></button>
          <button className="btn btn-ghost" style={{ height: 32, padding: '0 12px' }}><I.download/> Export</button>
        </div>
      </div>

      <table className="orders">
        <thead>
          <tr>
            <th onClick={() => toggleSort('id')} className={sortCol==='id' ? 'sorted' : ''}>Order ID <SortIco col="id"/></th>
            <th onClick={() => toggleSort('cust')} className={sortCol==='cust' ? 'sorted' : ''}>Customer <SortIco col="cust"/></th>
            <th onClick={() => toggleSort('product')} className={`hide-sm ${sortCol==='product' ? 'sorted' : ''}`}>Product <SortIco col="product"/></th>
            <th onClick={() => toggleSort('amount')} className={sortCol==='amount' ? 'sorted' : ''} style={{ textAlign: 'right' }}>Amount <SortIco col="amount"/></th>
            <th>Status</th>
            <th onClick={() => toggleSort('date')} className={`hide-sm ${sortCol==='date' ? 'sorted' : ''}`}>Date <SortIco col="date"/></th>
          </tr>
        </thead>
        <tbody>
          {sorted.map(o => (
            <tr key={o.id}>
              <td className="mono">{o.id}</td>
              <td>
                <div className="cust-cell">
                  <div className="avatar sm" style={{ background: `linear-gradient(135deg, ${o.grad[0]}, ${o.grad[1]})` }}>{o.init}</div>
                  <div>
                    <div className="nm">{o.cust}</div>
                    <div className="em">{o.em}</div>
                  </div>
                </div>
              </td>
              <td className="hide-sm">{o.product}</td>
              <td style={{ textAlign: 'right', fontWeight: 500 }}>${o.amount.toLocaleString()}</td>
              <td>
                <span className={`pill ${STATUS[o.status].cls}`}>
                  <span className="pill-dot"/>{STATUS[o.status].label}
                </span>
              </td>
              <td className="hide-sm" style={{ color: 'var(--text-dim)' }}>{o.date}</td>
            </tr>
          ))}
        </tbody>
      </table>

      <div className="pager">
        <div className="pg-info">Showing <span style={{ color: 'var(--text)' }}>{start}–{end}</span> of <span style={{ color: 'var(--text)' }}>{totalRows}</span> orders</div>
        <div className="pg-btns">
          <button className="pg-btn" disabled={page === 1} onClick={() => setPage(p => Math.max(1, p - 1))}><I.chevLeft/></button>
          {[1, 2, 3, 4, 5].map(n => (
            <button key={n} className={`pg-btn ${page === n ? 'active' : ''}`} onClick={() => setPage(n)}>{n}</button>
          ))}
          <span style={{ color: 'var(--text-muted)', padding: '0 4px', alignSelf: 'center' }}>…</span>
          <button className={`pg-btn ${page === totalPages ? 'active' : ''}`} onClick={() => setPage(totalPages)}>{totalPages}</button>
          <button className="pg-btn" disabled={page === totalPages} onClick={() => setPage(p => Math.min(totalPages, p + 1))}><I.chevRight/></button>
        </div>
      </div>
    </div>
  );
}

/* ============ Mobile bottom nav ============ */
function MobileBottomNav({ active, onSelect }) {
  const items = [
    { key: 'dashboard', label: 'Home', icon: I.home },
    { key: 'analytics', label: 'Analytics', icon: I.sAnalytics },
    { key: 'orders',    label: 'Orders', icon: I.sOrders },
    { key: 'customers', label: 'People', icon: I.sCustomers },
    { key: 'settings',  label: 'Settings', icon: I.sSettings },
  ];
  return (
    <nav className="mobile-bottom-nav">
      {items.map(it => {
        const Icn = it.icon;
        return (
          <button key={it.key} className={`mb-item ${active === it.key ? 'active' : ''}`} onClick={() => onSelect(it.key)}>
            <Icn size={19}/>
            <span>{it.label}</span>
            {active === it.key && <span className="mb-dot"/>}
          </button>
        );
      })}
    </nav>
  );
}

Object.assign(window, { WelcomeRow, KpiRow, RevenueChart, TopProducts, ActivityFeed, OrdersTable, MobileBottomNav });
