// Data display: DataTable, EmptyState, Skeleton, Progress, Pagination, Stepper, Breadcrumb
// Plus: EU currency & number helpers (de-DE locale, € primary)

// --- CURRENCY / NUMBER HELPERS ---
// € primary, German formatting: "1.234,56 €"
const euro = (n, opts = {}) => {
  if (n === 0 && opts.emptyDash) return '—';
  const { maxFrac = 2, minFrac = 2, compact = false } = opts;
  if (compact && Math.abs(n) >= 1000) {
    if (Math.abs(n) >= 1e6) return (n/1e6).toLocaleString('de-DE', { maximumFractionDigits: 1 }).replace(/,0$/, '') + ' Mio. €';
    if (Math.abs(n) >= 1000) return (n/1000).toLocaleString('de-DE', { maximumFractionDigits: 1 }).replace(/,0$/, '') + 'k €';
  }
  return n.toLocaleString('de-DE', { minimumFractionDigits: minFrac, maximumFractionDigits: maxFrac }) + ' €';
};
// For places where we need the number WITHOUT the € symbol (e.g. AnimateNumber wrapped)
const num = (n, opts = {}) => {
  const { maxFrac = 2, minFrac = 0 } = opts;
  return n.toLocaleString('de-DE', { minimumFractionDigits: minFrac, maximumFractionDigits: maxFrac });
};
// Integer formatter for counts (tickets, views, attendees): "48.218"
const count = (n) => n.toLocaleString('de-DE');
// Date helpers (German style, but abbreviated English month for UI brevity)
const germanDate = (d) => {
  if (typeof d === 'string') return d; // already formatted
  return d.toLocaleDateString('de-DE', { day: '2-digit', month: 'short', year: 'numeric' });
};
// VAT rate constant (standard German MwSt.)
const VAT_RATE = 0.19;

window.euro = euro; window.num = num; window.count = count; window.germanDate = germanDate; window.VAT_RATE = VAT_RATE;


// --- DATA TABLE (sort, select, bulk) ---
const DataTable = ({ columns, rows, selectable, onRowClick, rowKey = 'id', dense }) => {
  const [sort, setSort] = React.useState({ key: null, dir: 'asc' });
  const [selected, setSelected] = React.useState(new Set());
  const sortedRows = React.useMemo(() => {
    if (!sort.key) return rows;
    const col = columns.find(c => c.key === sort.key);
    return [...rows].sort((a, b) => {
      const av = col.sortValue ? col.sortValue(a) : a[sort.key];
      const bv = col.sortValue ? col.sortValue(b) : b[sort.key];
      if (av === bv) return 0;
      const r = av > bv ? 1 : -1;
      return sort.dir === 'asc' ? r : -r;
    });
  }, [rows, sort, columns]);

  const allSelected = rows.length > 0 && selected.size === rows.length;
  const toggleAll = () => setSelected(allSelected ? new Set() : new Set(rows.map(r => r[rowKey])));
  const toggle = k => setSelected(s => { const n = new Set(s); n.has(k) ? n.delete(k) : n.add(k); return n; });

  const rowH = dense ? 40 : 52;

  return (
    <div style={{ border: '1px solid var(--line)', borderRadius: 12, overflow: 'hidden', background: 'var(--bg-raised)' }}>
      {selected.size > 0 && (
        <div style={{
          display: 'flex', alignItems: 'center', gap: 12,
          padding: '10px 16px', background: 'var(--ink)', color: 'var(--bg)',
          fontSize: 13,
          animation: `slideInBottom ${MOTION.dur.fast}ms ${MOTION.ease.out}`,
        }}>
          <span style={{ fontWeight: 600 }}>{selected.size} selected</span>
          <div style={{ flex: 1 }}/>
          <button style={{ border: 0, background: 'transparent', color: 'var(--bg)', cursor: 'pointer', fontSize: 12.5, fontWeight: 500 }}>Export</button>
          <button style={{ border: 0, background: 'transparent', color: 'var(--bg)', cursor: 'pointer', fontSize: 12.5, fontWeight: 500 }}>Email</button>
          <button onClick={() => setSelected(new Set())} style={{ border: 0, background: 'transparent', color: 'var(--bg)', cursor: 'pointer', fontSize: 12.5, opacity: 0.7 }}>Clear</button>
        </div>
      )}
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
        <thead>
          <tr style={{ background: 'var(--bg-sunken)', borderBottom: '1px solid var(--line)' }}>
            {selectable && <th style={{ width: 40, padding: '10px 12px' }}>
              <input type="checkbox" checked={allSelected} onChange={toggleAll} style={{ cursor: 'pointer' }}/>
            </th>}
            {columns.map(c => (
              <th key={c.key} style={{
                padding: '10px 14px', textAlign: c.align || 'left',
                fontSize: 11, fontWeight: 600, color: 'var(--ink-3)',
                textTransform: 'uppercase', letterSpacing: '0.05em',
                cursor: c.sortable ? 'pointer' : 'default',
                userSelect: 'none', whiteSpace: 'nowrap',
              }}
                onClick={c.sortable ? () => setSort(s => ({
                  key: c.key, dir: s.key === c.key && s.dir === 'asc' ? 'desc' : 'asc'
                })) : undefined}>
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                  {c.label}
                  {c.sortable && sort.key === c.key && (
                    <Icon name={sort.dir === 'asc' ? 'arrowUp' : 'arrowDown'} size={11}/>
                  )}
                </span>
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {sortedRows.map(r => (
            <tr key={r[rowKey]}
              onClick={() => onRowClick?.(r)}
              style={{
                borderBottom: '1px solid var(--line)', height: rowH,
                cursor: onRowClick ? 'pointer' : 'default',
                transition: 'background 100ms',
                background: selected.has(r[rowKey]) ? 'var(--accent-soft)' : 'transparent',
              }}
              onMouseEnter={e => !selected.has(r[rowKey]) && (e.currentTarget.style.background = 'var(--bg-muted)')}
              onMouseLeave={e => (e.currentTarget.style.background = selected.has(r[rowKey]) ? 'var(--accent-soft)' : 'transparent')}
            >
              {selectable && <td style={{ padding: '0 12px' }} onClick={e => e.stopPropagation()}>
                <input type="checkbox" checked={selected.has(r[rowKey])} onChange={() => toggle(r[rowKey])} style={{ cursor: 'pointer' }}/>
              </td>}
              {columns.map(c => (
                <td key={c.key} style={{ padding: '0 14px', textAlign: c.align || 'left', color: 'var(--ink)' }}>
                  {c.render ? c.render(r) : r[c.key]}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

// --- EMPTY STATE ---
const EmptyState = ({ icon = 'calendar', title, desc, action, illustration }) => (
  <div style={{
    display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
    padding: '48px 24px', textAlign: 'center', gap: 4,
  }}>
    {illustration || (
      <div style={{
        width: 64, height: 64, borderRadius: 16,
        background: 'var(--bg-muted)',
        border: '1px solid var(--line)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        marginBottom: 12,
        color: 'var(--ink-3)',
      }}><Icon name={icon} size={26}/></div>
    )}
    <div className="display" style={{ fontSize: 20, fontWeight: 500, letterSpacing: '-0.01em' }}>{title}</div>
    {desc && <div style={{ fontSize: 13.5, color: 'var(--ink-3)', maxWidth: 380, lineHeight: 1.5, marginTop: 4 }}>{desc}</div>}
    {action && <div style={{ marginTop: 16 }}>{action}</div>}
  </div>
);

// --- SKELETON ---
const Skeleton = ({ w = '100%', h = 14, r = 6, style = {} }) => (
  <div style={{
    width: w, height: h, borderRadius: r,
    background: 'linear-gradient(90deg, var(--bg-muted) 0%, var(--bg-sunken) 50%, var(--bg-muted) 100%)',
    backgroundSize: '400px 100%',
    animation: 'shimmer 1.4s infinite linear',
    ...style,
  }}/>
);

// --- PROGRESS ---
const Progress = ({ value, max = 100, label, tone = 'accent', showValue, animate = true }) => {
  const pct = Math.min(100, (value / max) * 100);
  const bg = { accent: 'var(--accent)', success: 'var(--success)', warning: 'var(--warning)', danger: 'var(--danger)' }[tone];
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {(label || showValue) && (
        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, color: 'var(--ink-2)' }}>
          {label && <span style={{ fontWeight: 500 }}>{label}</span>}
          {showValue && <span style={{ fontFamily: 'var(--font-mono)', color: 'var(--ink-3)' }}>{Math.round(pct)}%</span>}
        </div>
      )}
      <div style={{ height: 6, borderRadius: 99, background: 'var(--bg-muted)', overflow: 'hidden' }}>
        <div style={{
          height: '100%', width: `${pct}%`, background: bg, borderRadius: 99,
          transition: animate ? `width ${MOTION.dur.slow}ms ${MOTION.ease.out}` : 'none',
        }}/>
      </div>
    </div>
  );
};

// --- CIRCULAR PROGRESS (radial) ---
const CircularProgress = ({ value, max = 100, size = 56, stroke = 5, label }) => {
  const pct = Math.min(1, value / max);
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  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} stroke="var(--bg-muted)" strokeWidth={stroke} fill="none"/>
        <circle cx={size/2} cy={size/2} r={r} stroke="var(--accent)" strokeWidth={stroke} fill="none"
          strokeDasharray={c} strokeDashoffset={c * (1 - pct)} strokeLinecap="round"
          style={{ transition: `stroke-dashoffset ${MOTION.dur.slow}ms ${MOTION.ease.out}` }}/>
      </svg>
      <div style={{
        position: 'absolute', inset: 0,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontSize: size * 0.22, fontWeight: 600, fontFamily: 'var(--font-mono)',
      }}>{label ?? `${Math.round(pct * 100)}%`}</div>
    </div>
  );
};

// --- PAGINATION ---
const Pagination = ({ page, pages, onChange }) => {
  const btn = { width: 32, height: 32, border: 0, borderRadius: 7, cursor: 'pointer', fontFamily: 'var(--font-mono)', fontSize: 12.5, fontWeight: 550 };
  const make = (p, label) => (
    <button key={p} onClick={() => onChange?.(p)} disabled={p === page}
      style={{ ...btn, background: p === page ? 'var(--ink)' : 'transparent', color: p === page ? 'var(--bg)' : 'var(--ink-2)' }}>
      {label ?? p}
    </button>
  );
  const nums = [];
  for (let i = 1; i <= pages; i++) {
    if (i === 1 || i === pages || Math.abs(i - page) <= 1) nums.push(i);
    else if (nums[nums.length - 1] !== '…') nums.push('…');
  }
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
      <button onClick={() => onChange?.(Math.max(1, page - 1))} disabled={page === 1}
        style={{ ...btn, background: 'transparent', color: 'var(--ink-2)', opacity: page === 1 ? 0.3 : 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <Icon name="chevronLeft" size={14}/>
      </button>
      {nums.map((n, i) => n === '…' ? (
        <span key={'d'+i} style={{ padding: '0 4px', color: 'var(--ink-4)' }}>…</span>
      ) : make(n))}
      <button onClick={() => onChange?.(Math.min(pages, page + 1))} disabled={page === pages}
        style={{ ...btn, background: 'transparent', color: 'var(--ink-2)', opacity: page === pages ? 0.3 : 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <Icon name="chevronRight" size={14}/>
      </button>
    </div>
  );
};

// --- STEPPER ---
const Stepper = ({ steps, current }) => (
  <div style={{ display: 'flex', alignItems: 'center', gap: 0 }}>
    {steps.map((s, i) => {
      const done = i < current;
      const active = i === current;
      return (
        <React.Fragment key={i}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <div style={{
              width: 26, height: 26, borderRadius: '50%',
              background: done ? 'var(--ink)' : active ? 'var(--accent)' : 'var(--bg-muted)',
              color: done || active ? '#fff' : 'var(--ink-3)',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              fontSize: 12, fontWeight: 600,
              border: active ? '3px solid var(--accent-soft)' : 'none',
              transition: 'all 220ms',
            }}>
              {done ? <Icon name="check" size={13}/> : i + 1}
            </div>
            <div style={{
              fontSize: 13, fontWeight: active ? 600 : 500,
              color: done || active ? 'var(--ink)' : 'var(--ink-3)',
            }}>{s}</div>
          </div>
          {i < steps.length - 1 && <div style={{
            flex: 1, height: 2, margin: '0 14px',
            background: done ? 'var(--ink)' : 'var(--line)',
            borderRadius: 99, transition: 'background 220ms',
          }}/>}
        </React.Fragment>
      );
    })}
  </div>
);

// --- BREADCRUMB ---
const Breadcrumb = ({ items }) => (
  <nav style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12.5, color: 'var(--ink-3)' }}>
    {items.map((it, i) => (
      <React.Fragment key={i}>
        {i > 0 && <Icon name="chevronRight" size={12} style={{ color: 'var(--ink-4)' }}/>}
        {it.onClick ? (
          <button onClick={it.onClick} style={{
            border: 0, background: 'transparent', padding: 0, cursor: 'pointer',
            color: 'var(--ink-3)', fontFamily: 'inherit', fontSize: 12.5, fontWeight: 500,
          }}>{it.label}</button>
        ) : (
          <span style={{ color: i === items.length - 1 ? 'var(--ink)' : 'var(--ink-3)', fontWeight: i === items.length - 1 ? 600 : 500 }}>{it.label}</span>
        )}
      </React.Fragment>
    ))}
  </nav>
);

// --- BANNER ---
const Banner = ({ tone = 'info', icon, title, desc, action, onClose }) => {
  const tones = {
    info:    { bg: 'oklch(0.96 0.03 255)', fg: 'oklch(0.36 0.14 265)', icon: 'info' },
    success: { bg: 'oklch(0.95 0.04 155)', fg: 'oklch(0.38 0.11 155)', icon: 'check' },
    warning: { bg: 'oklch(0.96 0.05 75)',  fg: 'oklch(0.42 0.13 65)',  icon: 'alert' },
    danger:  { bg: 'oklch(0.95 0.04 25)',  fg: 'oklch(0.42 0.15 25)',  icon: 'alert' },
  };
  const t = tones[tone];
  return (
    <div style={{
      display: 'flex', alignItems: 'flex-start', gap: 12,
      padding: '12px 14px', borderRadius: 10,
      background: t.bg, color: t.fg,
      border: `1px solid ${t.fg}20`,
    }}>
      <Icon name={icon || t.icon} size={18} style={{ flexShrink: 0, marginTop: 1 }}/>
      <div style={{ flex: 1 }}>
        {title && <div style={{ fontSize: 13, fontWeight: 600 }}>{title}</div>}
        {desc && <div style={{ fontSize: 12.5, opacity: 0.85, marginTop: 2, lineHeight: 1.5 }}>{desc}</div>}
      </div>
      {action}
      {onClose && <button onClick={onClose} style={{ border: 0, background: 'transparent', color: t.fg, cursor: 'pointer', padding: 2 }}>
        <Icon name="x" size={14}/>
      </button>}
    </div>
  );
};

// --- CONFETTI ---
const Confetti = ({ show, count = 40 }) => {
  if (!show) return null;
  const colors = ['var(--accent)', 'var(--success)', 'var(--indigo)', 'var(--warning)'];
  return (
    <Portal>
      <div style={{ position: 'fixed', inset: 0, pointerEvents: 'none', zIndex: 3000, overflow: 'hidden' }}>
        {Array.from({ length: count }).map((_, i) => (
          <div key={i} style={{
            position: 'absolute',
            top: -20, left: `${Math.random() * 100}%`,
            width: 8, height: 12,
            background: colors[i % colors.length],
            animation: `confetti-fall ${1.6 + Math.random()}s ${Math.random() * 0.5}s ease-in forwards`,
            transform: `rotate(${Math.random() * 360}deg)`,
          }}/>
        ))}
      </div>
    </Portal>
  );
};

// --- ANIMATED CHECK (for success states) ---
const AnimatedCheck = ({ size = 28 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24">
    <circle cx="12" cy="12" r="11" fill="var(--success)"/>
    <path d="M7 12.5l3.5 3.5L17 9" stroke="#fff" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"
      strokeDasharray="30" strokeDashoffset="30"
      style={{ animation: 'check-draw 500ms 100ms ease-out forwards' }}/>
  </svg>
);

Object.assign(window, {
  DataTable, EmptyState, Skeleton, Progress, CircularProgress,
  Pagination, Stepper, Breadcrumb, Banner, Confetti, AnimatedCheck,
});
