// ─── Shared primitives ──────────────────────────────────────────────────────
const { useState, useMemo, useEffect, useRef } = React;

// ── StatusBadge ────────────────────────────────────────────────────────────
function StatusBadge({ status }) {
  const map = {
    Cerrada:     { bg: 'bg-emerald-50',  fg: 'text-emerald-800',  dot: 'bg-emerald-600' },
    Pendiente:   { bg: 'bg-amber-50',    fg: 'text-amber-800',    dot: 'bg-amber-600'   },
    Reservada:   { bg: 'bg-amber-50',    fg: 'text-amber-800',    dot: 'bg-amber-600'   },
    Anulada:     { bg: 'bg-slate-100',   fg: 'text-slate-600',    dot: 'bg-slate-400'   },
    Vencido:     { bg: 'bg-rose-50',     fg: 'text-rose-800',     dot: 'bg-rose-600'    },
    Disponible:  { bg: 'bg-emerald-50',  fg: 'text-emerald-800',  dot: 'bg-emerald-600' },
    Alquilada:   { bg: 'bg-slate-100',   fg: 'text-slate-600',    dot: 'bg-slate-400'   },
    Vendida:     { bg: 'bg-slate-100',   fg: 'text-slate-600',    dot: 'bg-slate-400'   },
  };
  const s = map[status] || { bg: 'bg-slate-100', fg: 'text-slate-700', dot: 'bg-slate-500' };
  return (
    <span className={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-[11px] font-medium ${s.bg} ${s.fg}`}>
      <span className={`w-1.5 h-1.5 rounded-full ${s.dot}`} />
      {status}
    </span>
  );
}

// ── Currency toggle (ARS / USD) ────────────────────────────────────────────
function CurrencyToggle({ value, onChange }) {
  return (
    <div className="inline-flex items-center bg-slate-100 rounded-full p-0.5 text-[11px] font-medium">
      {['ARS', 'USD'].map(c => (
        <button key={c}
          onClick={() => onChange(c)}
          className={`px-3 py-1 rounded-full transition-colors ${value === c ? 'bg-white text-ink shadow-card' : 'text-slate-500 hover:text-ink'}`}>
          {c}
        </button>
      ))}
    </div>
  );
}

// ── KPI card ───────────────────────────────────────────────────────────────
function KPICard({ label, primary, secondary, delta, accent, mono, spark }) {
  const deltaUp = delta != null && delta >= 0;
  return (
    <div className="group relative bg-white rounded-md border border-slate-100 shadow-card p-5 hover:border-slate-200 transition-colors">
      <div className="flex items-start justify-between">
        <div className="text-[11px] uppercase tracking-[0.14em] text-slate-500 font-medium">{label}</div>
        {accent && <span className="w-1.5 h-1.5 rounded-full" style={{ background: accent }} />}
      </div>
      <div className={`mt-3 text-[28px] leading-none font-semibold tracking-tight text-ink ${mono ? 'font-mono' : ''}`}>{primary}</div>
      {secondary && <div className="mt-1.5 text-[13px] text-slate-500">{secondary}</div>}
      {delta != null && (
        <div className="mt-4 flex items-center justify-between">
          <span className={`inline-flex items-center gap-1 text-[12px] font-medium ${deltaUp ? 'text-emerald-700' : 'text-rose-700'}`}>
            {deltaUp ? <I.Up size={12} sw={2} /> : <I.Dn size={12} sw={2} />}
            {Math.abs(delta)}%
          </span>
          <span className="text-[11px] text-slate-400">vs mes anterior</span>
        </div>
      )}
      {spark && <div className="mt-3">{spark}</div>}
    </div>
  );
}

// ── Card (generic) ─────────────────────────────────────────────────────────
function Card({ title, action, children, className = '', pad = 'p-5' }) {
  return (
    <div className={`bg-white rounded-md border border-slate-100 shadow-card ${className}`}>
      {(title || action) && (
        <div className={`flex items-center justify-between px-5 pt-5 ${children ? 'pb-3' : 'pb-5'}`}>
          <h3 className="text-[13px] font-semibold text-ink tracking-tight">{title}</h3>
          {action}
        </div>
      )}
      <div className={title ? `px-5 pb-5 ${pad === 'p-5' ? '' : pad}` : pad}>{children}</div>
    </div>
  );
}

// ── Button ─────────────────────────────────────────────────────────────────
function Button({ variant = 'primary', size = 'md', children, icon, className = '', ...rest }) {
  const sizes = { sm: 'text-[12px] px-2.5 py-1.5 gap-1.5', md: 'text-[13px] px-3.5 py-2 gap-2' };
  const variants = {
    primary:  'bg-slate-700 text-white hover:bg-slate-800',
    gold:     'bg-gold text-slate-900 hover:bg-gold-deep hover:text-white',
    ghost:    'bg-transparent text-slate-700 hover:bg-slate-100',
    outline:  'border border-slate-200 text-slate-700 bg-white hover:border-slate-300',
    danger:   'border border-rose-200 text-rose-700 bg-white hover:bg-rose-50',
  };
  return (
    <button className={`inline-flex items-center justify-center font-medium rounded transition-colors ${sizes[size]} ${variants[variant]} ${className}`} {...rest}>
      {icon}
      {children}
    </button>
  );
}

// ── Broker avatar (initials chip) ──────────────────────────────────────────
function BrokerChip({ code, size = 22 }) {
  const b = BROKERS[code] || { nombre: code, color: '#677A88' };
  return (
    <div title={b.nombre}
      className="inline-flex items-center justify-center rounded-full text-white font-semibold ring-2 ring-white"
      style={{ width: size, height: size, background: b.color, fontSize: size * 0.42 }}>
      {code}
    </div>
  );
}
function BrokerStack({ codes }) {
  return (
    <div className="inline-flex -space-x-1.5">
      {codes.map(c => <BrokerChip key={c} code={c} />)}
    </div>
  );
}

// ── Channel icon (Leads) ───────────────────────────────────────────────────
function ChannelIcon({ canal }) {
  const map = {
    WhatsApp:  { c: '#1FA855', i: I.Wa },
    Instagram: { c: '#B33A8E', i: I.Ig },
    ZonaProp:  { c: '#FF6A00', i: I.Zp },
    Tokko:     { c: '#3D4F5C', i: I.Tk },
  };
  const m = map[canal] || { c: '#677A88', i: I.Spark };
  const Ico = m.i;
  return (
    <span title={canal} className="inline-flex items-center justify-center w-5 h-5 rounded" style={{ background: m.c + '18', color: m.c }}>
      <Ico size={12} sw={2} />
    </span>
  );
}

// ── Empty state ────────────────────────────────────────────────────────────
function Empty({ title, sub }) {
  return (
    <div className="py-14 flex flex-col items-center text-center">
      <div className="w-14 h-14 rounded-full placeholder-stripe border border-slate-200 mb-4" />
      <div className="text-sm font-semibold text-ink">{title}</div>
      {sub && <div className="text-[12px] text-slate-500 mt-1 max-w-[280px]">{sub}</div>}
    </div>
  );
}

// ── Section header (page-level) ────────────────────────────────────────────
function PageHeader({ crumbs, title, sub, actions }) {
  return (
    <div className="flex items-end justify-between mb-7">
      <div>
        <nav className="text-[11px] text-slate-500 mb-2 flex items-center gap-1.5">
          {crumbs.map((c, i) => (
            <React.Fragment key={i}>
              <span className={i === crumbs.length - 1 ? 'text-slate-700' : ''}>{c}</span>
              {i < crumbs.length - 1 && <span className="text-slate-300">/</span>}
            </React.Fragment>
          ))}
        </nav>
        <h1 className="font-serif text-[34px] leading-[1.1] text-ink tracking-tight whitespace-nowrap">{title}</h1>
        {sub && <div className="text-[13px] text-slate-500 mt-3">{sub}</div>}
      </div>
      {actions && <div className="flex items-center gap-2">{actions}</div>}
    </div>
  );
}

// ── Small UI atoms ─────────────────────────────────────────────────────────
function FilterPill({ label, active, onClick }) {
  return (
    <button onClick={onClick}
      className={`text-[12px] px-3 py-1.5 rounded-full border transition-colors ${active ? 'bg-slate-700 border-slate-700 text-white' : 'bg-white border-slate-200 text-slate-700 hover:border-slate-300'}`}>
      {label}
    </button>
  );
}

// ── Dropdown select (compact, label-on-control) ────────────────────────────
function Select({ label, value, options, onChange, w = 'w-44', icon: Ico }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  const current = options.find(o => o.value === value) || options[0];
  const isDefault = current?.value === options[0]?.value;

  return (
    <div ref={ref} className={`relative ${w}`}>
      <button
        onClick={() => setOpen(o => !o)}
        className={`w-full bg-white border rounded px-3 py-1.5 flex items-center gap-2 text-left transition-colors ${open ? 'border-slate-400' : 'border-slate-200 hover:border-slate-300'}`}>
        {Ico && <Ico size={13} className="text-slate-400 flex-shrink-0" />}
        <div className="flex-1 min-w-0">
          <div className="text-[9px] uppercase tracking-[0.12em] text-slate-400 leading-none font-medium">{label}</div>
          <div className={`text-[12.5px] leading-tight mt-0.5 truncate ${isDefault ? 'text-slate-500' : 'text-ink font-medium'}`}>
            {current?.label}
          </div>
        </div>
        <I.ChevronDn size={13} className={`text-slate-400 flex-shrink-0 transition-transform ${open ? 'rotate-180' : ''}`} />
      </button>
      {open && (
        <div className="absolute left-0 right-0 mt-1 bg-white border border-slate-100 rounded shadow-pop z-30 py-1 fade-in">
          {options.map(o => {
            const sel = o.value === value;
            return (
              <button key={o.value}
                onClick={() => { onChange(o.value); setOpen(false); }}
                className={`w-full text-left px-3 py-2 flex items-center gap-2.5 hover:bg-canvas transition-colors ${sel ? 'text-ink' : 'text-slate-700'}`}>
                {o.dot && <span className="w-1.5 h-1.5 rounded-full flex-shrink-0" style={{ background: o.dot }} />}
                <span className="text-[12.5px] flex-1 truncate">{o.label}</span>
                {o.count != null && <span className="text-[10.5px] font-mono text-slate-400">{o.count}</span>}
                {sel && <I.Check size={13} sw={2.5} className="text-slate-700" />}
              </button>
            );
          })}
        </div>
      )}
    </div>
  );
}

function SearchInput({ placeholder = 'Buscar…', value, onChange, w = 'w-64' }) {
  return (
    <div className={`relative ${w}`}>
      <I.Search size={14} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-slate-400" />
      <input
        value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder}
        className="w-full pl-8 pr-3 py-2 text-[13px] bg-white border border-slate-200 rounded text-ink placeholder-slate-400 focus:outline-none focus:border-slate-400" />
    </div>
  );
}

// ── CSV export helper ──────────────────────────────────────────────────────
function toCSV(rows, columns) {
  const escape = (v) => {
    const s = v == null ? '' : String(v);
    return /[",\n;]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
  };
  // Excel-es-AR likes semicolons because comma is decimal separator
  const sep = ';';
  const header = columns.map(c => escape(c.label)).join(sep);
  const body = rows.map(r => columns.map(c => {
    const v = typeof c.value === 'function' ? c.value(r) : r[c.key];
    return escape(v);
  }).join(sep)).join('\n');
  return '\uFEFF' + header + '\n' + body; // UTF-8 BOM so Excel opens accents correctly
}
function downloadCSV(name, rows, columns) {
  const csv = toCSV(rows, columns);
  const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `${name}.csv`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}

function ExportButton({ filename, rows, columns, count }) {
  const [done, setDone] = useState(false);
  const fire = () => {
    downloadCSV(filename, rows, columns);
    setDone(true);
    setTimeout(() => setDone(false), 1800);
  };
  return (
    <Button variant="outline" size="md" icon={done ? <I.Check size={14} sw={2.5} /> : <I.Download size={14} />} onClick={fire}>
      {done ? 'Exportado' : `Exportar${count != null ? ` · ${count}` : ''}`}
    </Button>
  );
}

// ── ScopeBanner — comunica al usuario que está viendo un subset filtrado por rol
// Aparece arriba de las listas (operaciones, leads, …) cuando el rol acota la vista.
function ScopeBanner({ kind, rol, user, total, visible }) {
  if (!rol || rol.opsScope === 'all' && rol.leadsScope === 'all') return null;
  const scope = kind === 'leads' ? rol.leadsScope : rol.opsScope;
  if (scope === 'all') return null;
  const me = user?.broker ? BROKERS[user.broker]?.nombre || user.nombre : user?.nombre;
  const teamName = user?.broker ? TEAMS[BROKERS[user.broker]?.team]?.nombre : null;
  const label =
    scope === 'team' ? `${teamName || 'tu equipo'} (incluye tus operaciones)` :
                       `${me || 'tu usuario'}`;
  return (
    <div className="mb-5 flex items-center gap-3 px-4 py-2.5 rounded border border-slate-100 bg-white shadow-card">
      <span className="inline-flex items-center justify-center w-7 h-7 rounded-full flex-shrink-0"
        style={{ background: rol.badge + '18', color: rol.badge }}>
        <I.Lock size={13} sw={2} />
      </span>
      <div className="flex-1 min-w-0">
        <div className="text-[12.5px] text-ink">
          Mostrando <span className="font-semibold">{visible}</span> de {total} {kind} <span className="text-slate-400">·</span>{' '}
          <span className="text-slate-500">alcance: {label}</span>
        </div>
        <div className="text-[10.5px] text-slate-500 mt-0.5">
          Tu rol <span className="font-medium" style={{ color: rol.badge }}>{rol.label}</span> sólo permite ver registros asignados a {scope === 'team' ? 'tu equipo' : 'vos'}.
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  StatusBadge, CurrencyToggle, KPICard, Card, Button,
  BrokerChip, BrokerStack, ChannelIcon, Empty, PageHeader, FilterPill, Select, SearchInput,
  toCSV, downloadCSV, ExportButton,
  ScopeBanner,
});
