// === MaxAMove KPI / Dashboard component library ===
// ===================================================
//
// Shared building blocks for any "metric panel" surface in the app:
// Dashboard, Financials P&L, customer-facing summaries, future reports.
//
// Why this file exists:
//   The Dashboard's hero+supporting layout (built 2026-05-04) is the canonical
//   way the CRM presents metrics. Promoting these components out of dashboard.jsx
//   means any view in the app can use the same patterns without re-implementing
//   them. Per the standing "build for handoff" rule — design system is shared,
//   not copy-pasted.
//
// Usage:
//   <KpiSection title="Profitability" icon="dollar-bill" theme={KPI_THEMES.profit}
//     hero={<KpiHero label="Gross Profit" value="$1,472" sub="58.7% margin"/>}
//     supporting={[
//       <KpiCompact key="m" label="Margin" value="58.7%" sub="Goal 65%"/>,
//       <KpiCompact key="a" label="Avg Job"  value="$736"/>,
//       <KpiCompact key="c" last label="Total Cost" value="$1,037"/>,
//     ]}/>
//
// Component reference:
//   • KpiSection  — labeled section card with theme color identity (4px accent
//                   strip, colored icon chip in header). Wraps a hero + 3 supporting.
//   • KpiHero     — featured metric (44px value, gradient-tinted bg, optional
//                   trend pill, optional visual element like a ProgressRing).
//   • KpiCompact  — supporting metric (24px value, colored identity dot, clean).
//   • ProgressRing — pure-SVG circular gauge for goal-progress visualization.
//   • InfoTooltip — small ⓘ icon with hover/tap explainer text.
//
// Theme presets (KPI_THEMES):
//   .brand    → teal #14C6BF — default, the MaxAMove identity color
//   .marketing → purple #a855f7 — established palette color
//   .profit   → green #16a34a — established success color
//   .alert    → amber #f59e0b — established warn color
//   .danger   → red #ef4444 — established destructive color
//
// All colors used are pre-existing in the MaxAMove palette — no new colors
// are introduced here per the brand-consistency rule.

// ─── INFO TOOLTIP ───────────────────────────────────────────────────────────
// Small ⓘ icon that explains what a metric means. Hover (desktop) or tap (mobile)
// to show; tap-outside or mouse-leave to dismiss.
// Used on every KPI label so non-coders / new owners can read panels without
// Googling "what does ROAS mean."
function InfoTooltip({ text }) {
  const [show, setShow] = React.useState(false);
  const [pos, setPos] = React.useState(null);  // viewport-clamped position
  const ref = React.useRef(null);
  const btnRef = React.useRef(null);

  // Compute tooltip position in viewport coords. Uses position: fixed so it
  // escapes any overflow:hidden / z-index clipping on ancestor cards. Width
  // is clamped to viewport so the tooltip never extends off-screen on phones.
  // Horizontal anchor is the centerpoint of the ⓘ icon — clamped so the
  // tooltip itself stays fully inside the viewport.
  function openAt() {
    if (!btnRef.current) return;
    const r = btnRef.current.getBoundingClientRect();
    const margin = 12;
    const maxW = 280;
    const width = Math.min(maxW, window.innerWidth - margin * 2);
    const anchorX = r.left + r.width / 2;
    let left = anchorX - width / 2;
    left = Math.max(margin, Math.min(window.innerWidth - width - margin, left));
    const bottom = window.innerHeight - r.top + 8;  // 8px gap between icon top and tooltip bottom
    setPos({ left, bottom, width, anchorX });
    setShow(true);
  }
  function closeIt() { setShow(false); setPos(null); }

  React.useEffect(() => {
    if (!show) return;
    const handle = (e) => { if (ref.current && !ref.current.contains(e.target)) closeIt(); };
    const onScroll = () => closeIt();   // dismiss on scroll so the popover doesn't drift
    document.addEventListener('click', handle);
    window.addEventListener('scroll', onScroll, true);
    window.addEventListener('resize', onScroll);
    return () => {
      document.removeEventListener('click', handle);
      window.removeEventListener('scroll', onScroll, true);
      window.removeEventListener('resize', onScroll);
    };
  }, [show]);

  return (
    <span ref={ref} style={{ position: 'relative', display: 'inline-flex', alignItems: 'center' }}
      onMouseEnter={openAt} onMouseLeave={closeIt}>
      <button ref={btnRef} type="button" aria-label="More info"
        onClick={(e) => { e.stopPropagation(); show ? closeIt() : openAt(); }}
        style={{ background: 'transparent', border: 'none', padding: 0, cursor: 'help', display: 'inline-flex', color: 'var(--muted)', lineHeight: 0 }}>
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2">
          <circle cx="12" cy="12" r="10"/>
          <line x1="12" y1="11" x2="12" y2="16"/>
          <circle cx="12" cy="8" r=".5" fill="currentColor"/>
        </svg>
      </button>
      {show && pos && (
        <div role="tooltip" style={{
          position: 'fixed',
          left: pos.left,
          bottom: pos.bottom,
          width: pos.width,
          background: '#0f172a', color: '#fff',
          padding: '10px 12px', borderRadius: 8,
          fontSize: 12, fontWeight: 500, lineHeight: 1.45,
          whiteSpace: 'normal', textAlign: 'left',
          boxShadow: '0 8px 24px rgba(0,0,0,0.25)',
          zIndex: 9999, textTransform: 'none', letterSpacing: 0,
          fontFamily: 'DM Sans, sans-serif',
          pointerEvents: 'auto',
        }}>
          {text}
          {/* Arrow at the bottom — points at the ⓘ icon centerpoint. Clamped
              within tooltip bounds so it doesn't float in mid-air on edge cases. */}
          <div style={{
            position: 'absolute', top: '100%',
            left: Math.max(8, Math.min(pos.width - 16, pos.anchorX - pos.left - 6)),
            width: 0, height: 0,
            borderLeft: '6px solid transparent', borderRight: '6px solid transparent',
            borderTop: '6px solid #0f172a',
          }}/>
        </div>
      )}
    </span>
  );
}

// ─── THEME PRESETS ──────────────────────────────────────────────────────────
// Each theme = { color (bold), tint (soft bg), dark (text on light bg) }.
// All values are pre-existing colors from the MaxAMove palette.
const KPI_THEMES = {
  brand:     { color: '#14C6BF', tint: '#f0fdfb', dark: '#0a9e98' }, // teal
  marketing: { color: '#a855f7', tint: '#faf5ff', dark: '#7e22ce' }, // purple (established)
  profit:    { color: '#16a34a', tint: '#f0fdf4', dark: '#15803d' }, // success green (established)
  alert:     { color: '#f59e0b', tint: '#fffbeb', dark: '#b45309' }, // amber (established)
  danger:    { color: '#ef4444', tint: '#fef2f2', dark: '#b91c1c' }, // destructive red (established)
  info:      { color: '#0ea5e9', tint: '#f0f9ff', dark: '#0369a1' }, // info blue (established)
};

// ─── KPI SECTION ────────────────────────────────────────────────────────────
// Labeled section card containing a hero metric on the left and 3 supporting
// metrics on the right. Theme color drives the accent strip and icon chip.
function KpiSection({ title, sub, icon, hero, supporting, theme }) {
  const t = theme || KPI_THEMES.brand;
  return (
    <div style={{ marginBottom: 24 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14, paddingLeft: 2 }}>
        <span style={{ width: 32, height: 32, borderRadius: 10, background: t.color, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', boxShadow: `0 4px 12px -2px ${t.color}55` }}>
          <Icon name={icon} size={17} color="#fff"/>
        </span>
        <h3 style={{ fontSize: 15, fontWeight: 800, fontFamily: 'Poppins', color: 'var(--text)', textTransform: 'none', letterSpacing: '-0.01em', margin: 0 }}>{title}</h3>
        {sub && <span style={{ fontSize: 12, color: 'var(--muted)', fontWeight: 500 }}>· {sub}</span>}
      </div>
      {/* IMPORTANT: no `overflow: hidden` here — the InfoTooltip popovers
          are absolutely positioned inside hero/compact cards and need to
          escape the section card boundary above. The accent strip at the
          top is a `border-top`, which paints inside the border-radius
          naturally so we don't need overflow clipping for it. */}
      <div className="kpi-shell" style={{ background: 'var(--card)', border: '1px solid var(--border)', borderTop: `4px solid ${t.color}`, borderRadius: 18, position: 'relative', boxShadow: '0 1px 3px rgba(15,23,42,0.04)' }}>
        <div className="kpi-row" style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr 1fr 1fr', gap: 0 }}>
          {hero && React.cloneElement(hero, { theme: t })}
          {(supporting || []).map((s, i) => React.cloneElement(s, { theme: t, key: s.key || i }))}
        </div>
      </div>
    </div>
  );
}

// ─── KPI HERO ───────────────────────────────────────────────────────────────
// Featured metric for a section. Big number, generous padding, optional trend
// pill, optional visual element (like a ProgressRing) on the right.
function KpiHero({ label, value, sub, subColor, info, trend, theme, visual }) {
  const t = theme || KPI_THEMES.brand;
  return (
    <div className="kpi-hero" style={{
      padding: '28px 30px 26px',
      borderRight: '1px solid var(--border)',
      position: 'relative',
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'space-between',
      minHeight: 156,
      background: `linear-gradient(135deg, ${t.tint} 0%, var(--card) 65%)`,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 14 }}>
        <span style={{ fontSize: 11, fontWeight: 800, textTransform: 'uppercase', letterSpacing: '0.11em', color: t.dark || 'var(--muted)' }}>{label}</span>
        {info && <InfoTooltip text={info}/>}
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', gap: 12 }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, flexWrap: 'wrap' }}>
            <div style={{ fontSize: 44, fontWeight: 900, fontFamily: 'Poppins', color: 'var(--text)', lineHeight: 1, letterSpacing: '-0.025em' }}>{value}</div>
            {trend && (
              <span style={{ fontSize: 12, fontWeight: 800, padding: '4px 10px', borderRadius: 999, background: trend.up ? '#dcfce7' : '#fee2e2', color: trend.up ? '#15803d' : '#b91c1c', display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                {trend.up ? '▲' : '▼'} {trend.label}
              </span>
            )}
          </div>
          {sub && <div style={{ fontSize: 13, marginTop: 10, color: subColor || 'var(--muted)', fontWeight: 600 }}>{sub}</div>}
        </div>
        {visual && <div style={{ flexShrink: 0 }}>{visual}</div>}
      </div>
    </div>
  );
}

// ─── KPI COMPACT ────────────────────────────────────────────────────────────
// Smaller supporting metric. Sits to the right of a KpiHero. Has a colored
// identity dot before the label for section continuity.
// Pass `last={true}` on the rightmost one to suppress the right divider.
function KpiCompact({ label, value, sub, subColor, info, last, theme }) {
  const t = theme || KPI_THEMES.brand;
  return (
    <div className={`kpi-compact${last ? ' kpi-compact-last' : ''}`} style={{ padding: '24px 20px 22px', borderRight: last ? 'none' : '1px solid var(--border)', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', minHeight: 156 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 5, marginBottom: 10 }}>
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: t.color, flexShrink: 0 }}/>
        <span style={{ fontSize: 10, fontWeight: 800, textTransform: 'uppercase', letterSpacing: '0.1em', color: 'var(--muted)' }}>{label}</span>
        {info && <InfoTooltip text={info}/>}
      </div>
      <div>
        <div style={{ fontSize: 24, fontWeight: 800, fontFamily: 'Poppins', color: 'var(--text)', lineHeight: 1.05, letterSpacing: '-0.01em' }}>{value}</div>
        {sub && <div style={{ fontSize: 11, marginTop: 6, color: subColor || 'var(--muted)', lineHeight: 1.4, fontWeight: 500 }}>{sub}</div>}
      </div>
    </div>
  );
}

// ─── PROGRESS RING ──────────────────────────────────────────────────────────
// Circular goal-progress gauge. Pure SVG, no library.
// Pass:
//   pct   — current value (e.g. 58.7 for 58.7%)
//   goal  — target value (e.g. 65)
//   color — stroke color (typically chosen by the caller based on goal-state)
//   label — small caption below the percentage (e.g. "of goal")
function ProgressRing({ pct, goal, color, label, size = 78 }) {
  const stroke = 7;
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const safePct = Math.max(0, Math.min(100, pct));
  // Ratio of goal achieved (0..1, capped at 1 for >100% performance).
  // Center number + arc both use this so they tell the same story:
  // "you're at X% of your goal." A raw safePct of 58.7 with a 65 goal
  // displays as 90% achieved, which matches the "OF GOAL" label. Without
  // capping, an over-target month could show >100% — capped here so the
  // ring + label stay coherent (use a sub-text to celebrate over-perform).
  const ratio = goal > 0 ? Math.min(1, safePct / goal) : 0;
  const off = c * (1 - ratio);
  const centerPct = Math.round(ratio * 100);
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--border)" strokeWidth={stroke}/>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={color} strokeWidth={stroke}
          strokeDasharray={c} strokeDashoffset={off} strokeLinecap="round"
          style={{ transition: 'stroke-dashoffset 600ms ease-out' }}/>
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', textAlign: 'center', lineHeight: 1.1 }}>
        <div style={{ fontSize: 14, fontWeight: 900, fontFamily: 'Poppins', color: color }}>{centerPct}%</div>
        {label && <div style={{ fontSize: 9, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginTop: 1 }}>{label}</div>}
      </div>
    </div>
  );
}

// ─── AVATAR ─────────────────────────────────────────────────────────────────
// Round profile photo with initials fallback. Used for crew members across the
// app — Settings → Crew, Crew HQ portal, on-job clock screen, job cards,
// kanban, customer portal "your crew" section.
//
// Pass:
//   src      — public URL of the photo (null/empty → renders initials chip)
//   name     — used to derive initials when no src
//   size     — diameter in px (default 36)
//   color    — background color of the initials chip (default brand teal)
//   ringColor — optional ring around the avatar (e.g. job-status color)
function Avatar({ src, name, size = 36, color = '#14C6BF', ringColor, alt }) {
  const initials = (name || '').split(/\s+/).filter(Boolean).slice(0, 2).map(s => s[0]).join('').toUpperCase() || '?';
  const ring = ringColor ? `0 0 0 2px ${ringColor}` : 'none';
  const fontSize = Math.max(10, Math.round(size * 0.38));
  const common = {
    width: size, height: size, borderRadius: '50%',
    flexShrink: 0, display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
    boxShadow: ring,
    overflow: 'hidden',
  };
  if (src) {
    return (
      <img src={src} alt={alt || name || 'avatar'}
        style={{ ...common, objectFit: 'cover', background: '#f1f5f9' }}
        onError={(e) => { e.currentTarget.style.display = 'none'; }}/>
    );
  }
  return (
    <span style={{
      ...common,
      background: color, color: '#fff',
      fontWeight: 800, fontSize, letterSpacing: '0.02em',
      fontFamily: 'Poppins, sans-serif',
    }}>{initials}</span>
  );
}

// Expose globally so any Babel-loaded JSX can use these components without imports.
window.KpiSection = KpiSection;
window.KpiHero = KpiHero;
window.KpiCompact = KpiCompact;
window.ProgressRing = ProgressRing;
window.InfoTooltip = InfoTooltip;
window.Avatar = Avatar;
window.KPI_THEMES = KPI_THEMES;
