/* global React, window */
// ============================================================================
// David Analytics — shared primitives (Icon + formatting helpers).
// Exported to window so every text/babel script can use them.
// ============================================================================

// ---- Lucide icon wrapper ---------------------------------------------------
function Icon({ name, size = 18 }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    el.innerHTML = `<i data-lucide="${name}"></i>`;
    if (window.lucide) window.lucide.createIcons();
    const svg = el.querySelector('svg');
    if (svg) { svg.setAttribute('width', size); svg.setAttribute('height', size); }
  }, [name, size]);
  return <span ref={ref} className="lic" style={{ display: 'inline-flex', alignItems: 'center' }} />;
}

// ---- Avatar initials + deterministic brand color ---------------------------
const AV_COLORS = ['#64748b', '#2563eb', '#0891b2', '#7c3aed', '#d97706', '#059669'];
function initials(name) {
  const parts = String(name).replace(/[^\p{L}\s.]/gu, '').trim().split(/\s+/);
  if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
  return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
}
function avColor(name) {
  let h = 0;
  for (let i = 0; i < String(name).length; i++) h = (h * 31 + String(name).charCodeAt(i)) >>> 0;
  return AV_COLORS[h % AV_COLORS.length];
}

// ---- Value formatting ------------------------------------------------------
const euro = (n) => (n === 0 || n == null ? '—' : '€ ' + Number(n).toLocaleString('nl-NL'));

// ---- Nederlandse naamopbouw ------------------------------------------------
// Een persoon heeft gestructureerde naamvelden. Voorletters en
// ondertekeningsnaam zijn berekende velden (afgeleid van de overige velden),
// maar mogen handmatig worden overschreven — dat wordt onthouden via een
// `*Auto`-vlag, zodat de UI een melding kan tonen.
const NAAM_TUSSENVOEGSELS = new Set([
  'van', 'de', 'der', 'den', 'ten', 'ter', 'te', 'het', 'op', 'aan', 'bij',
  'in', 'tot', 'voor', 'onder', 'over', "'t",
]);

function splitNaam(naam) {
  const tokens = String(naam || '').trim().split(/\s+/).filter(Boolean);
  if (tokens.length === 0) return { voornaam: '', tussenvoegsel: '', achternaam: '' };
  if (tokens.length === 1) return { voornaam: tokens[0], tussenvoegsel: '', achternaam: '' };
  const voornaam = tokens[0];
  const rest = tokens.slice(1);
  const particles = [];
  let i = 0;
  // verzamel aaneengesloten kleingeschreven tussenvoegsels, laat ≥1 token over
  while (i < rest.length - 1 && rest[i] === rest[i].toLowerCase() && NAAM_TUSSENVOEGSELS.has(rest[i].toLowerCase())) {
    particles.push(rest[i]); i++;
  }
  return { voornaam, tussenvoegsel: particles.join(' '), achternaam: rest.slice(i).join(' ') };
}

function computeVoorletters(voornaam) {
  return String(voornaam || '')
    .split(/[\s-]+/).filter(Boolean)
    .map((p) => p[0].toUpperCase() + '.')
    .join('');
}

function computeOndertekeningsnaam(voorletters, tussenvoegsel, achternaam) {
  return [voorletters, tussenvoegsel, achternaam]
    .map((s) => String(s || '').trim()).filter(Boolean).join(' ');
}

// Vul de gestructureerde naamvelden op basis van `naam` (idempotent).
function ensurePersonName(row) {
  if (!row || row.voornaam != null) return row;
  const { voornaam, tussenvoegsel, achternaam } = splitNaam(row.naam);
  row.voornaam = voornaam;
  row.tussenvoegsel = tussenvoegsel;
  row.achternaam = achternaam;
  row.voorletters = computeVoorletters(voornaam);
  row.voorlettersAuto = true;
  row.ondertekeningsnaam = computeOndertekeningsnaam(row.voorletters, tussenvoegsel, achternaam);
  row.ondertekeningsnaamAuto = true;
  return row;
}

function personNameCustom(row) {
  return (row.voorlettersAuto === false) || (row.ondertekeningsnaamAuto === false);
}

// Find the tone map for a given key by looking at a page's column defs (DRY).
function tonesFor(cfg, key) {
  const col = (cfg.columns || []).find((c) => c.key === key);
  return (col && col.tones) || {};
}

// ---- Avatar ----------------------------------------------------------------
// Reusable "bolletje" for an identity: round with initials (person) or a
// rounded square with an icon (org / record). Color derives from the name,
// or pass an explicit `color`. Everything is perfectly centered.
function Avatar({ name = '', kind = 'person', size = 36, color, icon, photo, className = '' }) {
  const isSquare = kind === 'org' || kind === 'record';
  const showIcon = Boolean(icon) || isSquare;
  const glyph = icon || (kind === 'org' ? 'building-2' : 'file-text');
  const style = {
    width: size,
    height: size,
    background: color || avColor(name),
    borderRadius: isSquare ? Math.max(8, Math.round(size * 0.26)) : '50%',
    fontSize: Math.round(size * 0.36),
  };
  return (
    <span className={`ff-avatar${className ? ' ' + className : ''}`} style={style}>
      {photo
        ? <img className="ff-avatar-img" src={photo} alt={name} />
        : showIcon ? <Icon name={glyph} size={Math.round(size * 0.44)} /> : initials(name)}
    </span>
  );
}

// ---- IconBubble ------------------------------------------------------------
// Reusable round (or rounded) chip holding a single centered icon. Used for
// timeline dots, empty-state icons and placeholders. Color it inline via
// bg/color, or hand it a className and let CSS set the tone.
function IconBubble({ icon, size = 30, bg, color, radius, iconSize, className = '' }) {
  const style = { width: size, height: size, borderRadius: radius != null ? radius : '50%' };
  if (bg) style.background = bg;
  if (color) style.color = color;
  return (
    <span className={`icon-bubble${className ? ' ' + className : ''}`} style={style}>
      <Icon name={icon} size={iconSize || Math.round(size * 0.5)} />
    </span>
  );
}

// ---- Berekende velden --------------------------------------------------------
// CalcHint toont een waarde met een formule-popover bij hover/focus: eerst de
// algemene formule (variabelen cursief, breuken gestapeld), daarna de
// invulling met de actuele waarden. Frac = gestapelde breuk, Va = variabele.
function Frac({ num, den }) {
  return (
    <span className="frac">
      <span className="fr-num">{num}</span>
      <span className="fr-den">{den}</span>
    </span>
  );
}
function Va({ children }) { return <i className="f-var">{children}</i>; }
function CalcHint({ name, value, formula, filled }) {
  const ref = React.useRef(null);
  const [pos, setPos] = React.useState(null);
  const show = () => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const below = r.top < 150; // te weinig ruimte boven → onder het veld tonen
    setPos({
      x: Math.round(r.left + r.width / 2),
      top: below ? Math.round(r.bottom + 9) : null,
      bottom: below ? null : Math.round(window.innerHeight - r.top + 9),
    });
  };
  const hide = () => setPos(null);
  // De popover rendert via een portal op <body> met position:fixed, zodat hij
  // nooit achter kaarten of andere componenten kan verdwijnen.
  const pop = pos ? ReactDOM.createPortal(
    <span
      className="calc-pop"
      role="tooltip"
      ref={(el) => {
        if (!el) return;
        const pr = el.getBoundingClientRect();
        let dx = 0;
        if (pr.left < 8) dx = 8 - pr.left;
        else if (pr.right > window.innerWidth - 8) dx = (window.innerWidth - 8) - pr.right;
        if (dx) el.style.left = (pos.x + dx) + 'px';
      }}
      style={{
        left: pos.x,
        top: pos.top != null ? pos.top : 'auto',
        bottom: pos.bottom != null ? pos.bottom : 'auto',
        transform: 'translateX(-50%)',
      }}
    >
      <span className="cp-name"><Icon name="sigma" size={12} />{name}</span>
      {formula && (
        <span className="cp-block">
          <span className="cp-sec">Formule</span>
          {formula}
        </span>
      )}
      {filled && (
        <span className="cp-block filled">
          <span className="cp-sec">Invulling</span>
          {filled}
        </span>
      )}
    </span>,
    document.body
  ) : null;
  return (
    <span
      className="calc"
      tabIndex={0}
      ref={ref}
      onMouseEnter={show}
      onMouseLeave={hide}
      onFocus={show}
      onBlur={hide}
    >
      <span className="calc-val">{value}</span>
      {pop}
    </span>
  );
}

Object.assign(window, { Icon, AV_COLORS, initials, avColor, euro, tonesFor, Avatar, IconBubble, Frac, Va, CalcHint, splitNaam, computeVoorletters, computeOndertekeningsnaam, ensurePersonName, personNameCustom });
