// ─── Mock data for the prototype ────────────────────────────────────────────
const ARS = (n) => new Intl.NumberFormat('es-AR', { style: 'currency', currency: 'ARS', maximumFractionDigits: 0 }).format(n);
const USD = (n) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(n);
const NUM = (n) => new Intl.NumberFormat('es-AR').format(n);

// Compact currency: $142,6M  ·  US$ 118,4k — used in dense KPI cards
const ARS_C = (n) => {
  const abs = Math.abs(n);
  if (abs >= 1_000_000) return '$ ' + (n / 1_000_000).toLocaleString('es-AR', { maximumFractionDigits: 1 }) + ' M';
  if (abs >= 1_000)     return '$ ' + (n / 1_000).toLocaleString('es-AR', { maximumFractionDigits: 0 }) + ' k';
  return '$ ' + n.toLocaleString('es-AR');
};
const USD_C = (n) => {
  const abs = Math.abs(n);
  if (abs >= 1_000_000) return 'US$ ' + (n / 1_000_000).toLocaleString('en-US', { maximumFractionDigits: 2 }) + 'M';
  if (abs >= 1_000)     return 'US$ ' + (n / 1_000).toLocaleString('en-US', { maximumFractionDigits: 1 }) + 'k';
  return 'US$ ' + n.toLocaleString('en-US');
};

const KPIS = {
  // Ingresos por categoría
  ingresos_brutos:      { ars: 142_580_000, usd: 118_400, delta: +12.4 },  // total operaciones cerradas
  ingresos_netos:       { ars: 104_320_000, usd: 86_650,  delta: +9.8 },   // bruto − comisiones a 3ros − gastos op
  ingresos_compartidos: { ars: 38_260_000,  usd: 31_750,  delta: +5.1 },   // pagado a otras inmobiliarias
  comisiones_propias:   { ars: 66_060_000,  usd: 54_900,  delta: +11.2 },  // sólo Lanven
  comisiones_pendientes:{ ars: 12_840_000,  usd: 10_650,  delta: -2.1, qty: 4 },
  // Costos
  gastos:               { ars: 38_240_000,  usd: 31_800,  delta: -3.1 },
  // Liquidez
  caja:                 { ars: 8_420_000,   usd: 24_650 },
  // Operación
  operaciones:          { count: 14, monto_usd: 2_840_000, delta: +2, ticket_avg_usd: 203_000 },
  pipeline_usd:         { value: 1_640_000, count: 9 },
  // Leads
  leads:                { activos: 47, nuevos_semana: 12, conversion: 18.4 },
  // Stock
  propiedades:          { total: 38, disponibles: 22, reservadas: 4, vendidas_mes: 6, alquiladas: 6 },
  // Top performer
  top_broker:           { code: 'SM', ops: 6, usd: 1_120_000 },
};

const CHART_6M = [
  { m: 'Dic', ing: 78,  eg: 28 },
  { m: 'Ene', ing: 92,  eg: 31 },
  { m: 'Feb', ing: 86,  eg: 34 },
  { m: 'Mar', ing: 118, eg: 36 },
  { m: 'Abr', ing: 128, eg: 41 },
  { m: 'May', ing: 142, eg: 38 },
]; // values in millones de ARS

// Canales por los que se concretó la operación — habilita atribución end-of-funnel
const CANALES_CIERRE = [
  { id: 'tokko',    label: 'Tokko Broker', short: 'Tokko',    color: '#3D4F5C' },
  { id: 'zonaprop', label: 'ZonaProp',     short: 'ZonaProp', color: '#FF6A00' },
  { id: 'whatsapp', label: 'WhatsApp',     short: 'WhatsApp', color: '#1FA855' },
  { id: 'referido', label: 'Referido',     short: 'Referido', color: '#A88A47' },
  { id: 'web',      label: 'Web propia',   short: 'Web',      color: '#677A88' },
];
const CANAL_BY_ID = Object.fromEntries(CANALES_CIERRE.map(c => [c.id, c]));

const OPERACIONES = [
  { id: 'OP-0142', fecha: '2026-05-18', propiedad: 'Av. Libertador 4820 · 3°B', barrio: 'Núñez',      tipo: 'Venta',    monto_usd: 285_000, m2: 92,  brokers: ['SM', 'JD'], team: 'norte',  canal: 'tokko',    comision: 4.0, estado: 'Cerrada' },
  { id: 'OP-0141', fecha: '2026-05-16', propiedad: 'Honduras 5410 · PB',          barrio: 'Palermo',    tipo: 'Alquiler', monto_usd: 1_800,   m2: 64,  brokers: ['LA'],       team: 'centro', canal: 'zonaprop', comision: 1.0, estado: 'Pendiente' },
  { id: 'OP-0140', fecha: '2026-05-14', propiedad: 'Palmera Nova · UF 308',       barrio: 'Núñez',      tipo: 'Venta',    monto_usd: 412_000, m2: 132, brokers: ['SM'],       team: 'norte',  canal: 'whatsapp', comision: 4.0, estado: 'Cerrada' },
  { id: 'OP-0139', fecha: '2026-05-12', propiedad: 'Olleros 2280 · 5°A',          barrio: 'Colegiales', tipo: 'Venta',    monto_usd: 198_500, m2: 58,  brokers: ['JD', 'MV'], team: 'norte',  canal: 'referido', comision: 4.0, estado: 'Reservada' },
  { id: 'OP-0138', fecha: '2026-05-09', propiedad: 'Soler 4119 · 2°C',            barrio: 'Palermo',    tipo: 'Alquiler', monto_usd: 1_250,   m2: 52,  brokers: ['LA'],       team: 'centro', canal: 'whatsapp', comision: 1.0, estado: 'Cerrada' },
  { id: 'OP-0137', fecha: '2026-05-06', propiedad: 'Pampa 2840 · PH',             barrio: 'Belgrano',   tipo: 'Venta',    monto_usd: 230_000, m2: 88,  brokers: ['MV'],       team: 'norte',  canal: 'tokko',    comision: 4.0, estado: 'Anulada' },
];

// ── Año a la fecha · operaciones cerradas previas (para balance anual y rankings) ──
// Se computan junto con las del array OPERACIONES — sólo aquellas con estado Cerrada/Alquilada
const OPERACIONES_YTD = [
  // Enero
  { id: 'OP-0098', fecha: '2026-01-09', barrio: 'Belgrano',    tipo: 'Venta',    monto_usd: 312_000, m2: 105, brokers: ['SM'],       team: 'norte',  canal: 'tokko',    estado: 'Cerrada' },
  { id: 'OP-0099', fecha: '2026-01-22', barrio: 'Núñez',       tipo: 'Venta',    monto_usd: 268_000, m2: 88,  brokers: ['JD'],       team: 'norte',  canal: 'zonaprop', estado: 'Cerrada' },
  { id: 'OP-0100', fecha: '2026-01-28', barrio: 'Palermo',     tipo: 'Alquiler', monto_usd: 1_650,   m2: 55,  brokers: ['LA'],       team: 'centro', canal: 'whatsapp', estado: 'Cerrada' },
  // Febrero
  { id: 'OP-0104', fecha: '2026-02-05', barrio: 'Núñez',       tipo: 'Venta',    monto_usd: 395_000, m2: 122, brokers: ['SM','MV'],  team: 'norte',  canal: 'referido', estado: 'Cerrada' },
  { id: 'OP-0106', fecha: '2026-02-14', barrio: 'Colegiales',  tipo: 'Alquiler', monto_usd: 1_400,   m2: 48,  brokers: ['LA'],       team: 'centro', canal: 'zonaprop', estado: 'Cerrada' },
  { id: 'OP-0108', fecha: '2026-02-26', barrio: 'Villa Crespo',tipo: 'Venta',    monto_usd: 178_000, m2: 62,  brokers: ['MV'],       team: 'centro', canal: 'web',      estado: 'Cerrada' },
  // Marzo
  { id: 'OP-0112', fecha: '2026-03-04', barrio: 'Belgrano',    tipo: 'Venta',    monto_usd: 245_000, m2: 84,  brokers: ['SM'],       team: 'norte',  canal: 'tokko',    estado: 'Cerrada' },
  { id: 'OP-0115', fecha: '2026-03-18', barrio: 'Palermo',     tipo: 'Alquiler', monto_usd: 1_750,   m2: 58,  brokers: ['JD'],       team: 'centro', canal: 'zonaprop', estado: 'Cerrada' },
  { id: 'OP-0117', fecha: '2026-03-25', barrio: 'Núñez',       tipo: 'Venta',    monto_usd: 488_000, m2: 145, brokers: ['SM'],       team: 'norte',  canal: 'referido', estado: 'Cerrada' },
  // Abril
  { id: 'OP-0123', fecha: '2026-04-08', barrio: 'Belgrano',    tipo: 'Venta',    monto_usd: 282_000, m2: 95,  brokers: ['MV'],       team: 'norte',  canal: 'tokko',    estado: 'Cerrada' },
  { id: 'OP-0125', fecha: '2026-04-12', barrio: 'Colegiales',  tipo: 'Alquiler', monto_usd: 1_350,   m2: 50,  brokers: ['LA'],       team: 'centro', canal: 'whatsapp', estado: 'Cerrada' },
  { id: 'OP-0128', fecha: '2026-04-19', barrio: 'Palermo',     tipo: 'Venta',    monto_usd: 326_000, m2: 102, brokers: ['JD','LA'],  team: 'centro', canal: 'zonaprop', estado: 'Cerrada' },
  { id: 'OP-0131', fecha: '2026-04-29', barrio: 'Núñez',       tipo: 'Alquiler', monto_usd: 2_100,   m2: 72,  brokers: ['SM'],       team: 'norte',  canal: 'whatsapp', estado: 'Cerrada' },
];

// Universo completo del año (incluye mes actual cerrado)
const TODAS_OPS_YTD = [
  ...OPERACIONES_YTD,
  ...OPERACIONES.filter(o => o.estado === 'Cerrada').map(o => ({ ...o })),
];

// ── Cajas y cuentas ────────────────────────────────────────────────────────
const CAJAS = [
  { id: 'alvaro', nombre: 'Caja Álvaro', tipo: 'efectivo', ars: 1_850_000,  usd: 18_400, color: '#3D4F5C' },
  // ⚠ Caja May acepta únicamente movimientos de tipo "reserva" — reglada por solo_reservas
  { id: 'may',    nombre: 'Caja May',    tipo: 'efectivo', ars:   920_000,  usd: 12_200, color: '#A88A47', solo_reservas: true },
  { id: 'chica',  nombre: 'Caja Chica',  tipo: 'efectivo', ars: 8_420_000,  usd: 24_650, color: '#3F8A6B' },
  { id: 'banco',  nombre: 'Cuenta bancaria',  alias: 'Galicia · 0010-4421-3', tipo: 'banco', ars: 24_180_000, usd:  8_600, color: '#677A88' },
];
const CAJAS_BY_ID = Object.fromEntries(CAJAS.map(c => [c.id, c]));

const FORMAS_PAGO = [
  { id: 'ef_ars',  label: 'Efectivo ARS',           short: 'Ef. ARS',  glyph: '$',  color: '#3F8A6B', cajas: ['alvaro','may','chica'] },
  { id: 'ef_usd',  label: 'Efectivo USD',           short: 'Ef. USD',  glyph: '$',  color: '#A88A47', cajas: ['alvaro','may','chica'] },
  { id: 'transf',  label: 'Transferencia bancaria', short: 'Transf.',  glyph: '⇄',  color: '#3D4F5C', cajas: ['banco'] },
  { id: 'tarjeta', label: 'Tarjeta corporativa',    short: 'Tarjeta',  glyph: '◧',  color: '#677A88', cajas: ['banco'] },
];
const FORMA_BY_ID = Object.fromEntries(FORMAS_PAGO.map(f => [f.id, f]));

const GASTOS = [
  { id: 'G-2241', fecha: '2026-05-20', area: 'MKT',       desc: 'Campaña Meta Ads — Núñez',          monto: 480_000, moneda: 'ARS', forma_pago: 'transf',  caja: 'banco',  comp: 'fact-2241.pdf' },
  { id: 'G-2240', fecha: '2026-05-19', area: 'OFFICE',    desc: 'Insumos oficina + café',            monto:  92_400, moneda: 'ARS', forma_pago: 'ef_ars',  caja: 'chica',  comp: 'fact-2240.pdf' },
  { id: 'G-2239', fecha: '2026-05-18', area: 'COMERCIAL', desc: 'Combustible visitas zona norte',    monto:  65_800, moneda: 'ARS', forma_pago: 'ef_ars',  caja: 'chica',  comp: 'fact-2239.pdf' },
  { id: 'G-2238', fecha: '2026-05-17', area: 'RRHH',      desc: 'Capacitación Tokko Broker',         monto:   1_200, moneda: 'USD', forma_pago: 'ef_usd',  caja: 'alvaro', comp: 'fact-2238.pdf' },
  { id: 'G-2237', fecha: '2026-05-15', area: 'GE',        desc: 'Honorarios contables abril',        monto: 850_000, moneda: 'ARS', forma_pago: 'transf',  caja: 'banco',  comp: 'fact-2237.pdf' },
  { id: 'G-2236', fecha: '2026-05-14', area: 'MKT',       desc: 'Producción fotos Palmera Nova',     monto: 320_000, moneda: 'ARS', forma_pago: 'tarjeta', caja: 'banco',  comp: null },
];

// ── Ingresos internos (ajenos a operaciones de venta/alquiler de clientes) ─
const INGRESO_CATS = ['Alquiler cochera', 'Alquiler oficina', 'Comisión renovación', 'Reintegro', 'Otros'];
const INGRESOS = [
  { id: 'IN-0048', fecha: '2026-05-20', concepto: 'Alquiler cochera · Olleros 2280',     categoria: 'Alquiler cochera',   monto:  95_000, moneda: 'ARS', caja: 'chica',  notas: 'Inquilino A. Rivas' },
  { id: 'IN-0047', fecha: '2026-05-15', concepto: 'Alquiler oficina · sala 2',           categoria: 'Alquiler oficina',   monto: 380_000, moneda: 'ARS', caja: 'banco',  notas: 'Estudio contable Vega' },
  { id: 'IN-0046', fecha: '2026-05-12', concepto: 'Reintegro proveedor fotografía',      categoria: 'Reintegro',          monto:   1_200, moneda: 'USD', caja: 'alvaro', notas: '' },
  { id: 'IN-0045', fecha: '2026-05-08', concepto: 'Comisión renovación · Soler 4119',    categoria: 'Comisión renovación',monto: 240_000, moneda: 'ARS', caja: 'banco',  notas: '' },
  { id: 'IN-0044', fecha: '2026-05-03', concepto: 'Alquiler cochera · Honduras 5410',    categoria: 'Alquiler cochera',   monto: 110_000, moneda: 'ARS', caja: 'chica',  notas: '' },
  { id: 'IN-0043', fecha: '2026-04-29', concepto: 'Alquiler oficina · sala 1',           categoria: 'Alquiler oficina',   monto: 320_000, moneda: 'ARS', caja: 'banco',  notas: '' },
];

// ── Movimientos entre cajas ────────────────────────────────────────────────
const MOVIMIENTOS = [
  { id: 'MV-0021', fecha: '2026-05-18', origen: 'chica',  destino: 'banco',  monto_o: 2_000,   mon_o: 'USD', tc: 1_180, monto_d: 2_360_000, mon_d: 'ARS', concepto: 'Depósito bancario USD → ARS', user: 'SM' },
  { id: 'MV-0020', fecha: '2026-05-14', origen: 'banco',  destino: 'alvaro', monto_o: 500_000, mon_o: 'ARS', tc: null,  monto_d:   500_000, mon_d: 'ARS', concepto: 'Retiro para honorarios',       user: 'AM' },
  { id: 'MV-0019', fecha: '2026-05-10', origen: 'may',    destino: 'chica',  monto_o: 1_000,   mon_o: 'USD', tc: null,  monto_d:     1_000, mon_d: 'USD', concepto: 'Traspaso efectivo USD',         user: 'MM' },
  { id: 'MV-0018', fecha: '2026-05-06', origen: 'banco',  destino: 'chica',  monto_o: 300_000, mon_o: 'ARS', tc: null,  monto_d:   300_000, mon_d: 'ARS', concepto: 'Reposición caja chica',         user: 'SM' },
];

const CAJA_MOV = [
  { id: 'CC-0421', fecha: '2026-05-20', tipo: 'Ingreso', concepto: 'Reposición Sofi',           ars: 500_000,  usd: null, tc: null,   saldo_ars: 8_420_000, saldo_usd: 24_650 },
  { id: 'CC-0420', fecha: '2026-05-19', tipo: 'Egreso',  concepto: 'Combustible · OP-0139',     ars: -65_800,  usd: null, tc: null,   saldo_ars: 7_920_000, saldo_usd: 24_650 },
  { id: 'CC-0419', fecha: '2026-05-18', tipo: 'Ingreso', concepto: 'Cobro seña Honduras 5410',  ars: null,     usd: 2_400, tc: 1180,  saldo_ars: 7_985_800, saldo_usd: 24_650 },
  { id: 'CC-0418', fecha: '2026-05-16', tipo: 'Egreso',  concepto: 'Tasa municipal · Olleros',  ars: -42_500,  usd: null, tc: null,   saldo_ars: 7_985_800, saldo_usd: 22_250 },
];

// ⚠ RESERVAS ahora carga 4 campos extra (punto 6 del brief):
//   - direccion           Dirección exacta de la reserva (texto libre)
//   - broker_sobre        Broker que entregó fisicamente el sobre con la seña
//   - monto_sobre + moneda Monto del sobre + moneda (ARS/USD)
//   - caja                Caja donde se guardó el sobre (alvaro | may)
const RESERVAS = [
  { id: 'R-0088', propiedad: 'Olleros 2280 · 5°A',     cliente: 'María Pereyra',  sena_usd: 9_900,  fecha: '2026-05-12', doc: 'reserva-0088.pdf',
    direccion: 'Olleros 2280, 5°A — Colegiales', broker_sobre: 'SM', monto_sobre: 9_900,  moneda_sobre: 'USD', caja: 'may' },
  { id: 'R-0087', propiedad: 'Honduras 5410 · PB',     cliente: 'Juan Saldívar',  sena_usd: 3_600,  fecha: '2026-05-09', doc: 'reserva-0087.pdf',
    direccion: 'Honduras 5410, PB — Palermo',     broker_sobre: 'LA', monto_sobre: 3_600,  moneda_sobre: 'USD', caja: 'alvaro' },
  { id: 'R-0086', propiedad: 'Palmera Nova · UF 308',  cliente: 'Carla Mendieta', sena_usd: 12_400, fecha: '2026-05-04', doc: 'reserva-0086.pdf',
    direccion: 'Av. del Libertador 4820, UF 308 — Núñez', broker_sobre: 'JD', monto_sobre: 12_400, moneda_sobre: 'USD', caja: 'may' },
];

const PROPIEDADES = [
  { id: 'P-301', dir: 'Av. Libertador 4820 · 3°B', barrio: 'Núñez',       tipo: 'Venta',    precio_usd: 285_000, amb: 3, m2: 92,  estado: 'Disponible', x: 0.28, y: 0.34 },
  { id: 'P-302', dir: 'Honduras 5410 · PB',        barrio: 'Palermo',     tipo: 'Alquiler', precio_usd: 1_800,   amb: 2, m2: 64,  estado: 'Reservada',  x: 0.46, y: 0.52 },
  { id: 'P-303', dir: 'Palmera Nova · UF 308',     barrio: 'Núñez',       tipo: 'Venta',    precio_usd: 412_000, amb: 4, m2: 132, estado: 'Disponible', x: 0.34, y: 0.28 },
  { id: 'P-304', dir: 'Olleros 2280 · 5°A',        barrio: 'Colegiales',  tipo: 'Venta',    precio_usd: 198_500, amb: 2, m2: 58,  estado: 'Reservada',  x: 0.41, y: 0.41 },
  { id: 'P-305', dir: 'Soler 4119 · 2°C',          barrio: 'Palermo',     tipo: 'Alquiler', precio_usd: 1_250,   amb: 2, m2: 52,  estado: 'Alquilada',  x: 0.49, y: 0.49 },
  { id: 'P-306', dir: 'Pampa 2840 · PH',           barrio: 'Belgrano',    tipo: 'Venta',    precio_usd: 230_000, amb: 3, m2: 88,  estado: 'Vendida',    x: 0.37, y: 0.39 },
  { id: 'P-307', dir: 'Cabildo 1980 · 7°D',        barrio: 'Belgrano',    tipo: 'Venta',    precio_usd: 168_000, amb: 2, m2: 54,  estado: 'Disponible', x: 0.39, y: 0.36 },
  { id: 'P-308', dir: 'Echeverría 2204 · 4°A',     barrio: 'Belgrano',    tipo: 'Alquiler', precio_usd: 2_200,   amb: 3, m2: 78,  estado: 'Disponible', x: 0.42, y: 0.37 },
];

const LEADS = [
  { id: 'L-1041', nombre: 'Florencia Aguirre', canal: 'WhatsApp',  score: 92, broker: 'SM', etapa: 'Nuevo',      last: 'hace 8 min',   interes: 'Núñez · 3 amb · venta' },
  { id: 'L-1040', nombre: 'Ramiro Quintana',   canal: 'Instagram', score: 71, broker: 'JD', etapa: 'Nuevo',      last: 'hace 42 min',  interes: 'Palermo · 2 amb · alquiler' },
  { id: 'L-1039', nombre: 'Lucía Sandoval',    canal: 'ZonaProp',  score: 84, broker: 'LA', etapa: 'Contactado', last: 'hace 2 h',     interes: 'Belgrano · venta' },
  { id: 'L-1038', nombre: 'Tomás Iribarne',    canal: 'Tokko',     score: 66, broker: 'JD', etapa: 'Contactado', last: 'hace 4 h',     interes: 'Colegiales · alquiler' },
  { id: 'L-1037', nombre: 'Daniela Cattaneo',  canal: 'WhatsApp',  score: 88, broker: 'SM', etapa: 'Calificado', last: 'ayer',         interes: 'Núñez · pozo · USD 400k' },
  { id: 'L-1036', nombre: 'Iván Berrutti',     canal: 'ZonaProp',  score: 78, broker: 'MV', etapa: 'Calificado', last: 'ayer',         interes: 'Villa Crespo · venta' },
  { id: 'L-1035', nombre: 'Mariana Costa',     canal: 'Instagram', score: 81, broker: 'LA', etapa: 'Derivado',   last: 'hace 2 días',  interes: 'San Fernando · pozo' },
  { id: 'L-1034', nombre: 'Esteban Roldán',    canal: 'WhatsApp',  score: 95, broker: 'SM', etapa: 'Cerrado',    last: 'hace 3 días',  interes: 'Palmera Nova · UF 308' },
];

const ETAPAS = ['Nuevo', 'Contactado', 'Calificado', 'Derivado', 'Cerrado'];

const ALERTAS = [
  { tipo: 'Vencimiento',  texto: 'Reserva R-0086 vence en 2 días',                fecha: '24/05', sev: 'warn' },
  { tipo: 'Comprobante',  texto: 'Gasto G-2236 sin comprobante adjunto',           fecha: 'hoy',   sev: 'bad'  },
  { tipo: 'Cobranza',     texto: 'Comisión OP-0141 pendiente de cobro · 5 días',  fecha: '27/05', sev: 'warn' },
  { tipo: 'Renovación',   texto: 'Alquiler Soler 4119 renueva el 30/05',          fecha: '30/05', sev: 'ok'   },
];

const BROKERS = {
  SM: { nombre: 'Sofía Marini',    color: '#3D4F5C', team: 'norte' },
  JD: { nombre: 'Julián Devoto',   color: '#A88A47', team: 'norte' },
  LA: { nombre: 'Lautaro Aguilar', color: '#3F8A6B', team: 'centro' },
  MV: { nombre: 'Mariana Vidal',   color: '#677A88', team: 'centro' },
};

// ── Equipos comerciales ────────────────────────────────────────────────────
const TEAMS = {
  norte:  { id: 'norte',  nombre: 'Team Norte',  zona: 'Núñez · Belgrano · Colegiales', lider: 'SM', color: '#3D4F5C' },
  centro: { id: 'centro', nombre: 'Team Centro', zona: 'Palermo · Villa Crespo',         lider: 'LA', color: '#3F8A6B' },
};

// ── Roles y permisos ──────────────────────────────────────────────────────
// Cada rol declara qué rutas puede ver y qué widgets de ranking acceder.
// Pasame los emails reales y los mapeo 1 a 1.
const ROLES = {
  admin: {
    label: 'Administración',
    desc:  'Acceso completo a todo el sistema',
    rutas: ['dashboard','operaciones','propiedades','leads','rankings','ingresos','gastos','cajas','movimientos','reservas','finanzas-dashboard','sueldos','usuarios'],
    rankings: ['equipos','vendedores','barrios'],
    opsScope: 'all', leadsScope: 'all',
    canEdit: true,
    badge: '#3D4F5C',
  },
  team_leader: {
    label: 'Team Leader',
    desc:  'Ve operaciones de su equipo + sus propios leads',
    rutas: ['dashboard','operaciones','propiedades','leads','rankings'],
    rankings: ['equipos','vendedores'],
    opsScope: 'team', leadsScope: 'own',
    canEdit: true,
    badge: '#A88A47',
  },
  broker: {
    label: 'Broker',
    desc:  'Sólo sus propias operaciones y leads',
    rutas: ['dashboard','operaciones','propiedades','leads'],
    rankings: [],
    opsScope: 'own', leadsScope: 'own',
    canEdit: false,
    badge: '#3F8A6B',
  },
  marketing: {
    label: 'Marketing',
    desc:  'Permisos de broker, pero ve TODOS los leads del sistema',
    rutas: ['dashboard','operaciones','propiedades','leads'],
    rankings: [],
    opsScope: 'own', leadsScope: 'all',
    canEdit: false,
    badge: '#B33A8E',
  },
  finanzas: {
    label: 'Finanzas',
    desc:  'Sólo módulos financieros y dashboard de movimientos',
    rutas: ['finanzas-dashboard','ingresos','gastos','cajas','movimientos','reservas','sueldos'],
    rankings: [],
    opsScope: 'all', leadsScope: 'all',
    canEdit: true,
    badge: '#677A88',
  },
};

// Listado mock de usuarios — reemplazar por emails reales
const USUARIOS = [
  { email: 'sofia@lanven.com.ar',     nombre: 'Sofía Marini',    rol: 'admin',       initials: 'SM', broker: 'SM' },
  { email: 'lautaro@lanven.com.ar',   nombre: 'Lautaro Aguilar', rol: 'team_leader', initials: 'LA', broker: 'LA' },
  { email: 'julian@lanven.com.ar',    nombre: 'Julián Devoto',   rol: 'broker',      initials: 'JD', broker: 'JD' },
  { email: 'mariana@lanven.com.ar',   nombre: 'Mariana Vidal',   rol: 'broker',      initials: 'MV', broker: 'MV' },
  { email: 'marketing@lanven.com.ar', nombre: 'Belén Otamendi',  rol: 'marketing',   initials: 'BO' },
  { email: 'finanzas@lanven.com.ar',  nombre: 'Alma Mansilla',   rol: 'finanzas',    initials: 'AM' },
];

// ── Helpers de filtrado por rol ─────────────────────────────────────
// Aplican opsScope / leadsScope: cada vista (lista, badge, KPI) muestra
// exactamente los registros que el usuario tiene permitido ver.
//   opsScope:    'all'  -> todas las ops    'team' -> equipo + propias    'own' -> sólo propias
//   leadsScope:  'all'  -> todos los leads  'own' -> sólo propios
function filterOpsForUser(user, ops) {
  if (!user || !ops) return ops || [];
  const rol = ROLES[user.rol]; if (!rol) return ops;
  if (rol.opsScope === 'all') return ops;
  const myCode = user.broker;
  if (rol.opsScope === 'team') {
    if (!myCode) return [];
    const myTeam = BROKERS[myCode]?.team;
    return ops.filter(o => (o.brokers || []).includes(myCode) || (myTeam && o.team === myTeam));
  }
  if (!myCode) return [];
  return ops.filter(o => (o.brokers || []).includes(myCode));
}

function filterLeadsForUser(user, leads) {
  if (!user || !leads) return leads || [];
  const rol = ROLES[user.rol]; if (!rol) return leads;
  if (rol.leadsScope === 'all') return leads;
  const myCode = user.broker;
  if (!myCode) return [];
  return leads.filter(l => l.broker === myCode);
}

Object.assign(window, {
  ARS, USD, NUM, ARS_C, USD_C,
  KPIS, CHART_6M, OPERACIONES, OPERACIONES_YTD, TODAS_OPS_YTD, GASTOS, CAJA_MOV, RESERVAS, PROPIEDADES, LEADS, ETAPAS, ALERTAS, BROKERS,
  CAJAS, CAJAS_BY_ID, FORMAS_PAGO, FORMA_BY_ID, INGRESOS, INGRESO_CATS, MOVIMIENTOS,
  CANALES_CIERRE, CANAL_BY_ID, TEAMS, ROLES, USUARIOS,
  filterOpsForUser, filterLeadsForUser,
});
