// ============================================================
// Componentes compartidos
// ============================================================
const { useState, useEffect, useMemo, useRef } = React;

// -------- Iconos SVG (minimalistas, line-icon style) --------
const Icon = ({ name, size = 16, style = {} }) => {
  const icons = {
    dashboard: <><rect x="3" y="3" width="7" height="9" rx="1"/><rect x="14" y="3" width="7" height="5" rx="1"/><rect x="14" y="12" width="7" height="9" rx="1"/><rect x="3" y="16" width="7" height="5" rx="1"/></>,
    book: <><path d="M4 4a1 1 0 0 1 1-1h5v18H5a1 1 0 0 1-1-1V4z"/><path d="M14 3h5a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1h-5V3z"/></>,
    camera: <><path d="M4 7h3l2-3h6l2 3h3a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1z"/><circle cx="12" cy="13" r="4"/></>,
    edit: <><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></>,
    check_shield: <><path d="M12 3l8 3v6c0 5-3.5 8.5-8 9-4.5-.5-8-4-8-9V6l8-3z"/><path d="M9 12l2 2 4-4"/></>,
    convert: <><path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/><path d="M9 15l3-3 3 3"/><path d="M12 12v6"/></>,
    fifo: <><rect x="3" y="4" width="18" height="4" rx="1"/><rect x="3" y="10" width="18" height="4" rx="1"/><rect x="3" y="16" width="18" height="4" rx="1"/></>,
    stats: <><path d="M3 20h18"/><rect x="5" y="12" width="3" height="8"/><rect x="10" y="7" width="3" height="13"/><rect x="15" y="14" width="3" height="6"/></>,
    plus: <><path d="M12 5v14"/><path d="M5 12h14"/></>,
    x: <><path d="M18 6L6 18M6 6l12 12"/></>,
    logout: <><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></>,
    calendar: <><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></>,
    clock: <><circle cx="12" cy="12" r="9"/><polyline points="12 7 12 12 15 14"/></>,
    users: <><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></>,
    filter: <><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></>,
    search: <><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></>,
    alert: <><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></>,
    check: <><polyline points="20 6 9 17 4 12"/></>,
    arrow_right: <><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></>,
    trending: <><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/></>,
    target: <><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></>,
    library: <><rect x="4" y="3" width="4" height="18"/><rect x="10" y="3" width="4" height="18"/><path d="M16 3l4 1-3 17-4-1z"/></>,
    plus_circle: <><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></>,
    settings: <><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></>,
  };
  const path = icons[name] || <circle cx="12" cy="12" r="8"/>;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" style={style}>
      {path}
    </svg>
  );
};

// -------- Avatar --------
const Avatar = ({ user, size = 'md' }) => {
  if (!user) return null;
  return (
    <div className={`avatar ${size !== 'md' ? size : ''}`} style={{ background: user.color }}>
      {user.iniciales}
    </div>
  );
};

// -------- Status pill --------
const StatusPill = ({ estatus }) => {
  const s = APP_DATA.ESTATUS[estatus];
  if (!s) return null;
  return (
    <span className="status-pill" style={{ background: s.bg, color: s.color }}>
      <span className="badge-dot" style={{ background: s.color }} />
      {s.label}
    </span>
  );
};

// -------- Progress bar --------
const ProgressBar = ({ value, max, color }) => {
  const pct = Math.min(100, (value / max) * 100);
  return (
    <div className="progress-bar-wrap">
      <div className="progress-bar-fill" style={{ width: pct + '%', background: color || 'var(--primary)' }} />
    </div>
  );
};

// -------- KPI Card --------
const KPI = ({ label, value, sub, progress, tone = 'primary' }) => {
  return (
    <div className={`kpi ${tone}`}>
      <div className="kpi-label">{label}</div>
      <div className="kpi-value">{value}</div>
      {sub && <div className="kpi-sub">{sub}</div>}
      {progress !== undefined && (
        <div className="kpi-progress">
          <div className="kpi-progress-bar" style={{ width: Math.min(100, progress) + '%' }} />
        </div>
      )}
    </div>
  );
};

// -------- Modal --------
const Modal = ({ open, onClose, title, children, footer, maxWidth = 640 }) => {
  useEffect(() => {
    if (!open) return;
    const h = (e) => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, [open, onClose]);

  if (!open) return null;
  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" style={{ maxWidth }} onClick={e => e.stopPropagation()}>
        <div className="modal-header">
          <div className="modal-title">{title}</div>
          <button className="modal-close" onClick={onClose}><Icon name="x" size={18}/></button>
        </div>
        <div className="modal-body">{children}</div>
        {footer && <div className="modal-footer">{footer}</div>}
      </div>
    </div>
  );
};

// -------- Empty state --------
const Empty = ({ icon = 'book', title, subtitle }) => (
  <div style={{ padding: '48px 24px', textAlign: 'center', color: 'var(--text-3)' }}>
    <div style={{ opacity: 0.5, marginBottom: 12 }}>
      <Icon name={icon} size={36} />
    </div>
    <div style={{ fontSize: 15, fontWeight: 500, color: 'var(--text-2)' }}>{title}</div>
    {subtitle && <div style={{ fontSize: 13, marginTop: 4 }}>{subtitle}</div>}
  </div>
);

// -------- Helpers --------
const fmtDate = (d) => {
  if (!d) return '—';
  const dt = new Date(d + 'T00:00:00');
  return dt.toLocaleDateString('es-MX', { day: '2-digit', month: 'short', year: 'numeric' });
};
const fmtNum = (n) => (n == null ? '—' : n.toLocaleString('es-MX'));

const daysBetween = (a, b) => {
  const da = new Date(a); const db = new Date(b);
  return Math.round((db - da) / 86400000);
};

const getUser = (id) => APP_DATA.USUARIOS.find(u => u.id === id);

// Expose globally
Object.assign(window, { Icon, Avatar, StatusPill, ProgressBar, KPI, Modal, Empty, fmtDate, fmtNum, daysBetween, getUser });
