// ─── Operaciones ────────────────────────────────────────────────────────────
function CanalChip({ id, size = 'sm' }) {
  const c = CANAL_BY_ID[id];
  if (!c) return <span className="text-slate-300 text-[11px]">—</span>;
  return (
    <span className={`inline-flex items-center gap-1.5 rounded font-medium ${size === 'sm' ? 'px-2 py-0.5 text-[11px]' : 'px-2.5 py-1 text-[12px]'}`}
      style={{ background: c.color + '14', color: c.color }}>
      <span className="w-1.5 h-1.5 rounded-full" style={{ background: c.color }} />
      {c.short}
    </span>
  );
}

function adaptarOperacion(op) {
  return {
    id:        op.id.slice(-6).toUpperCase(),
    _id:       op.id,
    fecha:     op.fecha?.slice(0, 10),
    tipo:      op.tipo === 'ALQUILER_TEMPORAL' ? 'Alquiler temporal' : op.tipo.charAt(0) + op.tipo.slice(1).toLowerCase(),
    tipo_raw:  op.tipo,
    propiedad: op.propiedad?.direccion  ?? 'Sin propiedad',
    propiedadId: op.propiedadId ?? null,
    barrio:    op.propiedad?.barrio     ?? '—',
    m2:        op.propiedad?.superficie ?? 0,
    monto_usd: op.montoUSD || 0,
    monto_ars: op.montoARS || 0,
    comision:  op.comisionPorcentaje || 0,
    comisionMonto: op.comisionMonto || 0,
    brokers:   [op.broker ? `${op.broker.nombre} ${op.broker.apellido}` : '—'],
    brokerId:  op.brokerId,
    teamLeaderId: op.teamLeaderId ?? null,
    estado:     op.estado.charAt(0) + op.estado.slice(1).toLowerCase(),
    estado_raw: op.estado,
    canal:      op.canal ?? null,
    notas:      op.notas,
    canalCierre: op.canalCierre ?? null,
  };
}

function Operaciones() {
  const user = window.CURRENT_USER;
  const rol  = user ? ROLES[user.rol] : null;

  const [opsBackend, setOpsBackend]   = useState([]);
  const [loading, setLoading]         = useState(true);
  const [propiedades, setPropiedades] = useState([]);
  const [brokers, setBrokers]         = useState([]);
  const [teamLeaders, setTeamLeaders] = useState([]);
  const [creating, setCreating]       = useState(false);

  useEffect(() => {
    fetch(`${API_BASE}/api/operaciones`, { credentials: 'include' })
      .then(r => r.json())
      .then(data => setOpsBackend((data.data || []).map(adaptarOperacion)))
      .finally(() => setLoading(false));
  }, []);

  useEffect(() => {
    Promise.all([
      fetch(`${API_BASE}/api/propiedades`, { credentials: 'include' }).then(r => r.json()),
      fetch(`${API_BASE}/api/usuarios?rol=BROKER`, { credentials: 'include' }).then(r => r.json()),
      fetch(`${API_BASE}/api/usuarios?rol=TEAM_LEADER`, { credentials: 'include' }).then(r => r.json()),
    ]).then(([props, bkrs, tls]) => {
      setPropiedades(Array.isArray(props) ? props : []);
      setBrokers(Array.isArray(bkrs) ? bkrs : []);
      setTeamLeaders(Array.isArray(tls) ? tls : []);
    }).catch(err => console.error('[operaciones aux fetch]', err));
  }, []);

  const opsVisible = opsBackend;

  const handleAnularOp = (data) => {
    setOpsBackend(prev => prev.map(o => o._id === data.id ? adaptarOperacion(data) : o));
    setSelected(null);
  };

  const handleUpdateOp = (data) => {
    const adaptada = adaptarOperacion(data);
    setOpsBackend(prev => prev.map(o => o._id === data.id ? adaptada : o));
    setSelected(adaptada);
  };

  const [estado, setEstado] = useState('Todas');
  const [tipo, setTipo] = useState('Todos');
  const [canal, setCanal] = useState('Todos');
  const [q, setQ] = useState('');
  const [selected, setSelected] = useState(null);

  const filtered = useMemo(() => opsVisible.filter(o =>
    (estado === 'Todas' || o.estado === estado) &&
    (tipo === 'Todos' || o.tipo === tipo) &&
    (canal === 'Todos' || o.canal === canal) &&
    (q === '' || o.propiedad.toLowerCase().includes(q.toLowerCase()) || o.id.toLowerCase().includes(q.toLowerCase()))
  ), [opsVisible, estado, tipo, canal, q]);

  const ytdScope    = useMemo(() => filterOpsForUser(user, TODAS_OPS_YTD), [user?.email]);
  const ytdCerradas = ytdScope.filter(o => o.estado === 'Cerrada');
  const m2Vendidos   = ytdCerradas.filter(o => o.tipo === 'Venta').reduce((s, o) => s + (o.m2 || 0), 0);
  const m2Alquilados = ytdCerradas.filter(o => o.tipo === 'Alquiler').reduce((s, o) => s + (o.m2 || 0), 0);
  const opsVendidas    = ytdCerradas.filter(o => o.tipo === 'Venta').length;
  const opsAlquiladas  = ytdCerradas.filter(o => o.tipo === 'Alquiler').length;
  const montoTotalUSD  = ytdCerradas.reduce((s, o) => s + (o.monto_usd || 0), 0);

  if (loading) return <div className="p-8 text-slate-500">Cargando operaciones…</div>;

  return (
    <div className="fade-in">
      <PageHeader
        crumbs={['Inicio', 'Operaciones']}
        title="Operaciones"
        sub={`${filtered.length} resultados · monto total ${USD(filtered.reduce((s, o) => s + o.monto_usd, 0))}${rol && rol.opsScope !== 'all' ? ` · alcance ${rol.opsScope === 'team' ? 'equipo' : 'propias'}` : ''}`}
        actions={
          <>
            <Button variant="outline" size="md" icon={<I.Download size={14} />}>Exportar</Button>
            <Button variant="primary" size="md" icon={<I.Plus size={14} sw={2} />} onClick={() => setCreating(true)}>Nueva operación</Button>
          </>
        }
      />

      {rol && rol.opsScope !== 'all' && (
        <ScopeBanner kind="operaciones" rol={rol} user={user} total={OPERACIONES.length} visible={opsVisible.length} />
      )}

      <div className="grid grid-cols-12 gap-4 mb-6">
        <div className="col-span-3 bg-white rounded-md border border-slate-100 shadow-card p-5">
          <div className="flex items-center justify-between">
            <div className="text-[10px] uppercase tracking-[0.14em] text-slate-500 font-medium">m² vendidos · YTD</div>
            <span className="text-[9px] font-mono text-slate-400">2026</span>
          </div>
          <div className="font-mono text-[26px] text-ink leading-none mt-3">{NUM(m2Vendidos)}<span className="text-[14px] text-slate-400 ml-1">m²</span></div>
          <div className="text-[11.5px] text-slate-500 mt-1.5">{opsVendidas} ventas cerradas</div>
          <div className="mt-3 h-1 bg-slate-50 rounded-full overflow-hidden">
            <div className="h-full" style={{ width: `${Math.min(100, m2Vendidos / 1500 * 100)}%`, background: '#3D4F5C' }} />
          </div>
          <div className="text-[10px] text-slate-400 mt-1 font-mono">meta anual · 1.500 m²</div>
        </div>
        <div className="col-span-3 bg-white rounded-md border border-slate-100 shadow-card p-5">
          <div className="flex items-center justify-between">
            <div className="text-[10px] uppercase tracking-[0.14em] text-slate-500 font-medium">m² alquilados · YTD</div>
            <span className="text-[9px] font-mono text-slate-400">2026</span>
          </div>
          <div className="font-mono text-[26px] text-ink leading-none mt-3">{NUM(m2Alquilados)}<span className="text-[14px] text-slate-400 ml-1">m²</span></div>
          <div className="text-[11.5px] text-slate-500 mt-1.5">{opsAlquiladas} alquileres cerrados</div>
          <div className="mt-3 h-1 bg-slate-50 rounded-full overflow-hidden">
            <div className="h-full" style={{ width: `${Math.min(100, m2Alquilados / 800 * 100)}%`, background: '#3F8A6B' }} />
          </div>
          <div className="text-[10px] text-slate-400 mt-1 font-mono">meta anual · 800 m²</div>
        </div>
        <div className="col-span-3 bg-white rounded-md border border-slate-100 shadow-card p-5">
          <div className="text-[10px] uppercase tracking-[0.14em] text-slate-500 font-medium">Monto operado · YTD</div>
          <div className="font-mono text-[26px] text-ink leading-none mt-3">{USD_C(montoTotalUSD)}</div>
          <div className="text-[11.5px] text-slate-500 mt-1.5">{ytdCerradas.length} operaciones cerradas</div>
          <div className="mt-3 flex items-center gap-1 text-[11px] text-emerald-700"><I.Up size={11} sw={2} /> +18.4% vs 2025</div>
        </div>
        <div className="col-span-3 bg-white rounded-md border border-slate-100 shadow-card p-5">
          <div className="text-[10px] uppercase tracking-[0.14em] text-slate-500 font-medium">Atribución · canal de cierre</div>
          <CanalAttribStrip ops={ytdCerradas} />
        </div>
      </div>

      <div className="flex items-center gap-2.5 mb-4 flex-wrap">
        <SearchInput value={q} onChange={setQ} placeholder="Buscar por propiedad u OP-ID…" />
        <div className="h-8 w-px bg-slate-200 mx-1" />
        <Select label="Tipo" value={tipo} onChange={setTipo} w="w-40"
          options={[
            { value: 'Todos',    label: 'Todos los tipos', count: opsVisible.length },
            { value: 'Venta',    label: 'Venta',           count: opsVisible.filter(o => o.tipo === 'Venta').length },
            { value: 'Alquiler', label: 'Alquiler',        count: opsVisible.filter(o => o.tipo === 'Alquiler').length },
          ]} />
        <Select label="Estado" value={estado} onChange={setEstado} w="w-44"
          options={[
            { value: 'Todas',     label: 'Todos los estados', count: opsVisible.length },
            { value: 'Cerrada',   label: 'Cerrada',   dot: '#3F8A6B', count: opsVisible.filter(o => o.estado === 'Cerrada').length },
            { value: 'Pendiente', label: 'Pendiente', dot: '#B98A2E', count: opsVisible.filter(o => o.estado === 'Pendiente').length },
            { value: 'Reservada', label: 'Reservada', dot: '#C9A961', count: opsVisible.filter(o => o.estado === 'Reservada').length },
            { value: 'Anulada',   label: 'Anulada',   dot: '#8A9AA5', count: opsVisible.filter(o => o.estado === 'Anulada').length },
          ]} />
        <Select label="Canal de cierre" value={canal} onChange={setCanal} w="w-52"
          options={[
            { value: 'Todos', label: 'Todos los canales', count: opsVisible.length },
            ...CANALES_CIERRE.map(c => ({ value: c.id, label: c.label, dot: c.color, count: opsVisible.filter(o => o.canal === c.id).length })),
          ]} />
        {(tipo !== 'Todos' || estado !== 'Todas' || canal !== 'Todos' || q) && (
          <button onClick={() => { setTipo('Todos'); setEstado('Todas'); setCanal('Todos'); setQ(''); }}
            className="text-[11.5px] text-slate-500 hover:text-ink inline-flex items-center gap-1 px-2 py-1">
            <I.X size={12} /> Limpiar filtros
          </button>
        )}
      </div>

      <Card pad="p-0">
        <table className="w-full text-[12.5px]">
          <thead className="bg-slate-50/60">
            <tr className="text-[10px] uppercase tracking-[0.1em] text-slate-500 text-left">
              <th className="font-medium py-3 px-5">ID</th>
              <th className="font-medium">Fecha</th>
              <th className="font-medium">Propiedad</th>
              <th className="font-medium">Tipo</th>
              <th className="font-medium text-right">m²</th>
              <th className="font-medium text-right">Monto</th>
              <th className="font-medium text-right">% Com.</th>
              <th className="font-medium">Brokers</th>
              <th className="font-medium">Canal cierre</th>
              <th className="font-medium">Estado</th>
              <th className="font-medium px-3"></th>
            </tr>
          </thead>
          <tbody>
            {filtered.map(op => (
              <tr key={op.id}
                onClick={() => setSelected(op)}
                className="border-t border-slate-100 tr-hover cursor-pointer">
                <td className="py-3.5 px-5 font-mono text-[11.5px] text-slate-500">{op.id}</td>
                <td className="text-slate-600 font-mono text-[11.5px]">{op.fecha}</td>
                <td className="text-ink">{op.propiedad}</td>
                <td className="text-slate-600">{op.tipo}</td>
                <td className="text-right text-slate-600 font-mono">{op.m2}</td>
                <td className="text-right font-mono text-ink">{USD(op.monto_usd)}</td>
                <td className="text-right text-slate-600 font-mono">{op.comision}%</td>
                <td><BrokerStack codes={op.brokers} /></td>
                <td><CanalChip id={op.canal} /></td>
                <td><StatusBadge status={op.estado} /></td>
                <td className="px-3 text-slate-400"><I.Chevron size={14} /></td>
              </tr>
            ))}
          </tbody>
        </table>
        {filtered.length === 0 && <Empty title="Sin operaciones" sub="Ajustá los filtros o creá una nueva operación." />}
      </Card>

      {selected && (
        <OperacionDetail
          op={selected}
          onClose={() => setSelected(null)}
          onAnular={handleAnularOp}
          onUpdate={handleUpdateOp}
          propiedades={propiedades}
          brokers={brokers}
          teamLeaders={teamLeaders}
        />
      )}
      {creating && (
        <OperacionForm
          onClose={() => setCreating(false)}
          onSave={(nueva) => { setOpsBackend(prev => [nueva, ...prev]); setCreating(false); }}
          propiedades={propiedades}
          brokers={brokers}
          teamLeaders={teamLeaders}
        />
      )}
    </div>
  );
}

// ── Atribución por canal ──────────────────────────────────────────────────
function CanalAttribStrip({ ops }) {
  const total = ops.length || 1;
  const byCanal = CANALES_CIERRE.map(c => ({
    ...c,
    n: ops.filter(o => o.canal === c.id).length,
  })).filter(x => x.n > 0).sort((a, b) => b.n - a.n);

  return (
    <div className="mt-3">
      <div className="flex h-2 rounded-full overflow-hidden bg-slate-50">
        {byCanal.map(c => (
          <div key={c.id} title={`${c.label} · ${c.n}`}
            style={{ width: `${c.n / total * 100}%`, background: c.color }} />
        ))}
      </div>
      <ul className="mt-2.5 space-y-1">
        {byCanal.slice(0, 3).map(c => (
          <li key={c.id} className="flex items-center justify-between text-[11px]">
            <span className="inline-flex items-center gap-1.5">
              <span className="w-1.5 h-1.5 rounded-full" style={{ background: c.color }} />
              <span className="text-slate-600">{c.short}</span>
            </span>
            <span className="font-mono text-slate-700">{c.n} <span className="text-slate-400 text-[10px]">· {Math.round(c.n/total*100)}%</span></span>
          </li>
        ))}
      </ul>
    </div>
  );
}

// ── Detail panel ──────────────────────────────────────────────────────────
function OperacionDetail({ op, onClose, onAnular, onUpdate, propiedades, brokers, teamLeaders }) {
  const [editing, setEditing] = useState(false);
  const [canalSaving, setCanalSaving] = useState(false);

  const handleAnular = () => {
    if (!confirm('¿Anular esta operación?')) return;
    fetch(`${API_BASE}/api/operaciones/${op._id}`, {
      method: 'PUT',
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ estado: 'ANULADA' }),
    })
      .then(r => r.json())
      .then(data => {
        if (data.error) { alert(data.error); return; }
        onAnular(data);
      })
      .catch(err => {
        console.error('[operaciones.anular]', err);
        alert('Error al anular operación.');
      });
  };

  const handleCanalChange = (canalId) => {
    if (canalSaving) return;
    setCanalSaving(true);
    fetch(`${API_BASE}/api/operaciones/${op._id}`, {
      method: 'PUT',
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ canal: canalId }),
    })
      .then(r => r.json())
      .then(data => {
        if (data.error) { alert(data.error); return; }
        onUpdate(data);
      })
      .catch(err => console.error('[operaciones.canal]', err))
      .finally(() => setCanalSaving(false));
  };

  if (editing) {
    return (
      <OperacionForm
        operacion={op}
        onClose={() => setEditing(false)}
        onSave={(actualizada) => { onUpdate(actualizada); setEditing(false); }}
        propiedades={propiedades}
        brokers={brokers}
        teamLeaders={teamLeaders}
      />
    );
  }

  return (
    <div className="fixed inset-0 z-30 flex">
      <div className="absolute inset-0 bg-ink/30 backdrop-blur-[2px]" onClick={onClose} />
      <div className="relative ml-auto h-full w-[460px] bg-white shadow-pop flex flex-col fade-in">
        <div className="px-6 py-5 border-b border-slate-100 flex items-start justify-between">
          <div>
            <div className="font-mono text-[11px] text-slate-500">{op.id}</div>
            <h2 className="font-serif text-[24px] leading-tight text-ink mt-0.5">{op.propiedad}</h2>
            <div className="mt-2 flex items-center gap-2">
              <StatusBadge status={op.estado} />
              <span className="text-[12px] text-slate-500">{op.tipo} · {op.fecha}</span>
            </div>
          </div>
          <button onClick={onClose} className="p-1.5 -mr-1.5 rounded hover:bg-slate-100 text-slate-500"><I.X size={16} /></button>
        </div>
        <div className="flex-1 overflow-y-auto px-6 py-5">
          <div className="grid grid-cols-2 gap-4 mb-6">
            <div>
              <div className="text-[10px] uppercase tracking-[0.12em] text-slate-400">Monto</div>
              <div className="font-mono text-[22px] text-ink mt-1">{USD(op.monto_usd)}</div>
              <div className="text-[11px] text-slate-500 mt-0.5">≈ {ARS(op.monto_usd * 1180.5)}</div>
            </div>
            <div>
              <div className="text-[10px] uppercase tracking-[0.12em] text-slate-400">Comisión total</div>
              <div className="font-mono text-[22px] text-ink mt-1">{USD(op.monto_usd * op.comision / 100)}</div>
              <div className="text-[11px] text-slate-500 mt-0.5">{op.comision}% del monto</div>
            </div>
            <div>
              <div className="text-[10px] uppercase tracking-[0.12em] text-slate-400">m² de la operación</div>
              <div className="font-mono text-[22px] text-ink mt-1">{op.m2} m²</div>
              <div className="text-[11px] text-slate-500 mt-0.5">computa al balance YTD</div>
            </div>
            <div>
              <div className="text-[10px] uppercase tracking-[0.12em] text-slate-400">Canal de cierre</div>
              <div className="mt-1.5"><CanalChip id={op.canal} size="md" /></div>
              <div className="text-[11px] text-slate-500 mt-1.5">origen real de la operación</div>
            </div>
          </div>

          {/* Selector de canal — persiste en backend */}
          <div className="bg-canvas border border-slate-100 rounded p-3 mb-6">
            <div className="text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-2">Cambiar canal de cierre</div>
            <div className="flex flex-wrap gap-1.5">
              {CANALES_CIERRE.map(c => (
                <button key={c.id}
                  onClick={() => handleCanalChange(c.id)}
                  disabled={canalSaving}
                  className={`text-[11.5px] px-2.5 py-1 rounded border transition-colors inline-flex items-center gap-1.5 ${op.canal === c.id ? 'border-transparent text-white' : 'bg-white border-slate-200 text-slate-600 hover:border-slate-300'}`}
                  style={op.canal === c.id ? { background: c.color } : undefined}>
                  <span className="w-1.5 h-1.5 rounded-full" style={op.canal === c.id ? { background: '#fff' } : { background: c.color }} />
                  {c.short}
                </button>
              ))}
            </div>
            <div className="mt-2 text-[10.5px] text-slate-500">Mantener atribución preservada incluso luego de cerrar la operación.</div>
          </div>

          <div className="text-[11px] uppercase tracking-[0.12em] text-slate-400 mb-2">Distribución</div>
          <div className="space-y-2">
            {op.brokers.map((b, i) => {
              const share = i === 0 ? (op.brokers.length > 1 ? 60 : 100) : 40 / (op.brokers.length - 1);
              return (
                <div key={b} className="flex items-center gap-3 px-3 py-2.5 bg-canvas rounded border border-slate-100">
                  <BrokerChip code={b} />
                  <div className="flex-1 text-[13px] text-ink">{b}</div>
                  <div className="text-[11px] text-slate-500 font-mono">{share}%</div>
                  <div className="font-mono text-[13px] text-ink w-[80px] text-right">{USD(op.monto_usd * op.comision / 100 * share / 100)}</div>
                </div>
              );
            })}
          </div>

          <div className="mt-6 pt-5 border-t border-slate-100 text-[11px] uppercase tracking-[0.12em] text-slate-400 mb-2">Historial</div>
          <ul className="space-y-3 text-[12px]">
            <li className="flex gap-3"><span className="font-mono text-slate-400">18/05</span><span className="text-ink">Operación cerrada — escritura firmada</span></li>
            <li className="flex gap-3"><span className="font-mono text-slate-400">15/05</span><span className="text-slate-600">Reserva confirmada</span></li>
            <li className="flex gap-3"><span className="font-mono text-slate-400">02/05</span><span className="text-slate-600">Reserva ingresada</span></li>
          </ul>
        </div>
        <div className="px-6 py-4 border-t border-slate-100 flex items-center gap-2 bg-canvas">
          {window.CURRENT_USER?.rol === 'admin' && (
            <Button variant="outline" size="md" onClick={() => setEditing(true)}>Editar</Button>
          )}
          <Button variant="danger" size="md" onClick={handleAnular}>Anular</Button>
          <div className="flex-1" />
          <Button variant="gold" size="md">Ver propiedad</Button>
        </div>
      </div>
    </div>
  );
}

// ── Form: crear y editar operación ────────────────────────────────────────
function OperacionForm({ operacion, onClose, onSave, propiedades, brokers, teamLeaders }) {
  const isEdit = !!operacion;
  const today  = new Date().toISOString().slice(0, 10);

  const [form, setForm] = useState({
    fecha:              operacion?.fecha              || today,
    tipo:               operacion?.tipo_raw           || 'VENTA',
    brokerId:           operacion?.brokerId           || '',
    propiedadId:        operacion?.propiedadId        || '',
    teamLeaderId:       operacion?.teamLeaderId       || '',
    montoUSD:           operacion ? String(operacion.monto_usd || '')  : '',
    montoARS:           operacion ? String(operacion.monto_ars || '')  : '',
    comisionPorcentaje: operacion ? String(operacion.comision  || '')  : '',
    notas:              operacion?.notas              || '',
    estado:             operacion?.estado_raw         || 'BORRADOR',
    canalCierre:        operacion?.canalCierre        || '',
  });
  const [touched, setTouched] = useState({});
  const [saving, setSaving]   = useState(false);
  const [err, setErr]         = useState(null);

  const REQ   = ['fecha', 'tipo', 'brokerId'];
  // canalCierre requerido solo en edición cuando estado=COBRADA
  const extraREQ = isEdit && form.estado === 'COBRADA' ? ['canalCierre'] : [];
  const valid = [...REQ, ...extraREQ].every(k => !!form[k]);
  const errF  = (k) => (touched[k] || touched.__submit) && !form[k];

  const set   = (k, v) => setForm(p => ({ ...p, [k]: v }));
  const touch = (k)    => setTouched(p => ({ ...p, [k]: true }));

  const submit = () => {
    setTouched(p => ({ ...p, __submit: true }));
    if (!valid) return;
    setSaving(true);
    setErr(null);

    const body = {
      fecha:              form.fecha,
      tipo:               form.tipo,
      brokerId:           form.brokerId,
      propiedadId:        form.propiedadId        || undefined,
      teamLeaderId:       form.teamLeaderId        || undefined,
      montoUSD:           form.montoUSD           ? Number(form.montoUSD)           : undefined,
      montoARS:           form.montoARS           ? Number(form.montoARS)           : undefined,
      comisionPorcentaje: form.comisionPorcentaje ? Number(form.comisionPorcentaje) : undefined,
      notas:              form.notas              || undefined,
      ...(isEdit ? { estado: form.estado } : {}),
      ...(isEdit && form.canalCierre ? { canalCierre: form.canalCierre } : {}),
    };

    const url    = isEdit ? `${API_BASE}/api/operaciones/${operacion._id}` : `${API_BASE}/api/operaciones`;
    const method = isEdit ? 'PUT' : 'POST';

    fetch(url, {
      method,
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    })
      .then(r => r.json())
      .then(data => {
        if (data.error) { setErr(data.error); setSaving(false); return; }
        onSave(adaptarOperacion(data));
      })
      .catch(e => {
        console.error('[operacion.save]', e);
        setErr('Error al guardar operación.');
        setSaving(false);
      });
  };

  return (
    <div className="fixed inset-0 z-30 flex">
      <div className="absolute inset-0 bg-ink/30 backdrop-blur-[2px]" onClick={onClose} />
      <div className="relative ml-auto h-full w-[460px] bg-white shadow-pop flex flex-col fade-in">
        <div className="px-6 py-5 border-b border-slate-100 flex items-start justify-between">
          <div>
            <h2 className="font-serif text-[24px] leading-tight text-ink">
              {isEdit ? 'Editar operación' : 'Nueva operación'}
            </h2>
            <p className="text-[12px] text-slate-500 mt-0.5">
              {isEdit ? `ID · ${operacion.id}` : 'Completá los datos de la operación'}
            </p>
          </div>
          <button onClick={onClose} className="p-1.5 -mr-1.5 rounded hover:bg-slate-100 text-slate-500"><I.X size={16} /></button>
        </div>
        <div className="flex-1 overflow-y-auto px-6 py-5 space-y-4">

          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">
                Tipo <span className="text-red-400">*</span>
              </label>
              <select value={form.tipo} onChange={e => set('tipo', e.target.value)} onBlur={() => touch('tipo')}
                className={`w-full text-[13px] px-3 py-2 rounded border ${errF('tipo') ? 'border-red-300 bg-red-50' : 'border-slate-200 bg-white'} outline-none focus:border-slate-400`}>
                <option value="VENTA">Venta</option>
                <option value="ALQUILER">Alquiler</option>
                <option value="ALQUILER_TEMPORAL">Alquiler temporal</option>
              </select>
            </div>
            <div>
              <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">
                Fecha <span className="text-red-400">*</span>
              </label>
              <input type="date" value={form.fecha} onChange={e => set('fecha', e.target.value)} onBlur={() => touch('fecha')}
                className={`w-full text-[13px] px-3 py-2 rounded border ${errF('fecha') ? 'border-red-300 bg-red-50' : 'border-slate-200 bg-white'} outline-none focus:border-slate-400`} />
            </div>
          </div>

          <div>
            <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">
              Broker <span className="text-red-400">*</span>
            </label>
            <select value={form.brokerId} onChange={e => set('brokerId', e.target.value)} onBlur={() => touch('brokerId')}
              className={`w-full text-[13px] px-3 py-2 rounded border ${errF('brokerId') ? 'border-red-300 bg-red-50' : 'border-slate-200 bg-white'} outline-none focus:border-slate-400`}>
              <option value="">— Seleccionar broker —</option>
              {(brokers || []).map(b => <option key={b.id} value={b.id}>{b.nombre} {b.apellido}</option>)}
            </select>
          </div>

          <div>
            <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">Propiedad{isEdit && <span className="ml-1 text-[9px] text-slate-400 normal-case tracking-normal">(referencia)</span>}</label>
            {isEdit ? (
              <div className="text-[13px] px-3 py-2 rounded border border-slate-100 bg-canvas text-ink">
                {operacion?.propiedad || '— Sin propiedad —'}
              </div>
            ) : (
              <select value={form.propiedadId} onChange={e => set('propiedadId', e.target.value)}
                className="w-full text-[13px] px-3 py-2 rounded border border-slate-200 bg-white outline-none focus:border-slate-400">
                <option value="">— Sin propiedad asignada —</option>
                {(propiedades || []).map(p => <option key={p.id} value={p.id}>{p.direccion}</option>)}
              </select>
            )}
          </div>

          <div>
            <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">Team Leader</label>
            <select value={form.teamLeaderId} onChange={e => set('teamLeaderId', e.target.value)}
              className="w-full text-[13px] px-3 py-2 rounded border border-slate-200 bg-white outline-none focus:border-slate-400">
              <option value="">— Sin team leader —</option>
              {(teamLeaders || []).map(tl => <option key={tl.id} value={tl.id}>{tl.nombre} {tl.apellido}</option>)}
            </select>
          </div>

          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">Monto USD</label>
              <input type="number" min="0" value={form.montoUSD} onChange={e => set('montoUSD', e.target.value)} placeholder="0"
                className="w-full text-[13px] px-3 py-2 rounded border border-slate-200 bg-white outline-none focus:border-slate-400" />
            </div>
            <div>
              <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">Monto ARS</label>
              <input type="number" min="0" value={form.montoARS} onChange={e => set('montoARS', e.target.value)} placeholder="0"
                className="w-full text-[13px] px-3 py-2 rounded border border-slate-200 bg-white outline-none focus:border-slate-400" />
            </div>
          </div>

          <div>
            <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">Comisión (%)</label>
            <input type="number" min="0" max="100" step="0.01" value={form.comisionPorcentaje} onChange={e => set('comisionPorcentaje', e.target.value)} placeholder="0.00"
              className="w-full text-[13px] px-3 py-2 rounded border border-slate-200 bg-white outline-none focus:border-slate-400" />
          </div>

          {/* Estado — solo en edición */}
          {isEdit && (
            <div>
              <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">Estado</label>
              <select value={form.estado} onChange={e => set('estado', e.target.value)}
                className="w-full text-[13px] px-3 py-2 rounded border border-slate-200 bg-white outline-none focus:border-slate-400">
                <option value="BORRADOR">Borrador</option>
                <option value="CONFIRMADA">Confirmada</option>
                <option value="COBRADA">Cobrada</option>
                <option value="ANULADA">Anulada</option>
              </select>
            </div>
          )}

          {/* Canal de cierre — solo en edición y cuando estado=COBRADA */}
          {isEdit && form.estado === 'COBRADA' && (
            <div>
              <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">
                Canal de cierre <span className="text-red-400">*</span>
              </label>
              <select value={form.canalCierre} onChange={e => set('canalCierre', e.target.value)}
                className={`w-full text-[13px] px-3 py-2 rounded border ${errF('canalCierre') ? 'border-red-300 bg-red-50' : 'border-slate-200 bg-white'} outline-none focus:border-slate-400`}>
                <option value="">— Seleccionar canal —</option>
                <option value="PORTAL">Portal</option>
                <option value="WHATSAPP">WhatsApp</option>
                <option value="INSTAGRAM">Instagram</option>
                <option value="REFERIDO">Referido</option>
                <option value="DIRECTO">Directo</option>
              </select>
              {errF('canalCierre') && (
                <div className="mt-1 text-[10.5px] text-rose-600">Requerido cuando el estado es Cobrada</div>
              )}
            </div>
          )}

          <div>
            <label className="block text-[10px] uppercase tracking-[0.12em] text-slate-500 mb-1.5">Notas</label>
            <textarea value={form.notas} onChange={e => set('notas', e.target.value)} placeholder="Observaciones…" rows={3}
              className="w-full text-[13px] px-3 py-2 rounded border border-slate-200 bg-white outline-none focus:border-slate-400 resize-none" />
          </div>

          {err && <div className="text-[12px] text-rose-700 bg-rose-50 border border-rose-200 rounded px-3 py-2">{err}</div>}
        </div>
        <div className="px-6 py-4 border-t border-slate-100 flex items-center gap-2 bg-canvas">
          <Button variant="outline" size="md" onClick={onClose}>Cancelar</Button>
          <div className="flex-1" />
          <Button variant="primary" size="md" onClick={submit} disabled={saving}>
            {saving ? 'Guardando…' : (isEdit ? 'Guardar cambios' : 'Crear operación')}
          </Button>
        </div>
      </div>
    </div>
  );
}

window.Operaciones = Operaciones;
window.CanalChip = CanalChip;
