// =========================================================================
// ALTA INTELIGENTE — Formulario condicional por tipo de inmueble
//
// ESCRITURA REAL a Supabase (tabla `inmuebles`). Tres capas, en este orden:
//   1. CAPTURA    — todos los campos son controlados (value + onChange → `f`).
//                   Antes ~20 inputs no tenían binding: el formulario ni
//                   siquiera retenía lo que el usuario tecleaba.
//   2. VALIDACIÓN — bloquea el guardado si falta lo imprescindible.
//   3. PERSISTENCIA — insert + recarga de DATA + apertura de la ficha creada.
//
// La tabla solo exige `ref` (NOT NULL + UNIQUE, autogenerada) y `tipo`.
// Lo condicional por tipo va a `caracteristicas` (jsonb) para no necesitar una
// columna nueva por cada tipo de inmueble.
// =========================================================================

const TYPES = [
  { key: "PISO", label: "Piso", db: "piso" },
  { key: "CASA", label: "Casa", db: "casa" },
  { key: "CHALET", label: "Chalet", db: "chalet" },
  { key: "LOCAL", label: "Local", db: "local" },
  { key: "NAVE", label: "Nave", db: "nave" },
  { key: "TRASPASO", label: "Traspaso", db: "traspaso" },
  { key: "GARAJE", label: "Garaje", db: "garaje" },
  { key: "OFICINA", label: "Oficina", db: "oficina" },
  { key: "TERRENO", label: "Terreno", db: "terreno" },
  { key: "PARCELA", label: "Parcela", db: "parcela" },
  { key: "TRASTERO", label: "Trastero", db: "trastero" },
  { key: "EDIFICIO", label: "Edificio", db: "edificio" },
];

// Clases del enum `clase_energetica`: A–G + exento + en_tramite.
const CLASES_ENERG = [
  { v: "A", l: "A" }, { v: "B", l: "B" }, { v: "C", l: "C" }, { v: "D", l: "D" },
  { v: "E", l: "E" }, { v: "F", l: "F" }, { v: "G", l: "G" },
  { v: "exento", l: "Exento" }, { v: "en_tramite", l: "En trámite" },
];

// "145.000" → 145000 · "12,5" → 12.5 · "" → null (el usuario escribe en es-ES)
const numOrNull = (s) => {
  if (s == null || String(s).trim() === "") return null;
  const limpio = String(s).replace(/\s/g, "").replace(/\./g, "").replace(",", ".");
  const n = Number(limpio.replace(/[^\d.-]/g, ""));
  return Number.isFinite(n) ? n : NaN;
};
// Un 0 ELEGIDO se guarda como 0, no como hueco: `Math.trunc(v) || null` convertía
// «0 dormitorios» (un local) en «no consta», que es otra cosa distinta.
const intOrNull = (v) => {
  if (v == null || v === "") return null;
  const n = Math.trunc(Number(v));
  return Number.isFinite(n) ? n : null;
};
const txtOrNull = (s) => { const t = (s || "").trim(); return t === "" ? null : t; };

const _injectAltaStyles = () => {
  if (document.getElementById("alta-styles")) return;
  const s = document.createElement("style");
  s.id = "alta-styles";
  s.textContent = `
    .input.err, .select.err { border-color: var(--danger); box-shadow: 0 0 0 2px var(--danger-bg); }
    .field-err { font-size: 11px; color: var(--danger); margin-top: 4px; font-weight: 600; }
    .alta-banner { display: flex; align-items: flex-start; gap: 10px; padding: 12px 16px; margin-bottom: 16px;
      border-radius: 4px; font-size: 13px; font-weight: 500; border: 1px solid; }
    .alta-banner.err  { background: var(--danger-bg);  color: var(--danger-fg);  border-color: var(--danger); }
    .alta-banner.ok   { background: var(--success-bg); color: var(--success-fg); border-color: var(--success); }
    .alta-banner.warn { background: var(--warning-bg); color: var(--warning-fg); border-color: var(--warning); }
    .alta-banner b { font-weight: 800; text-transform: uppercase; letter-spacing: .03em; }
    .bloque-off { opacity: .55; pointer-events: none; filter: grayscale(1); }
  `;
  document.head.appendChild(s);
};
_injectAltaStyles();

// B1 — SIN VALOR NO ES CERO. El campo nace vacío y sigue vacío hasta que alguien
// lo toca: un stepper que muestra «3» afirma tres dormitorios igual de fuerte que
// un desplegable marcado, y ese 3 acababa en la base sin que nadie lo eligiera.
// El «−» sobre un campo vacío no hace nada; el «+» arranca en 1.
const StepperNum = ({ value, onChange }) => {
  const vacio = value == null || value === "";
  return (
    <div className="stepper-num">
      <button type="button" onClick={() => onChange(vacio ? null : Math.max(0, value - 1))}>−</button>
      <input
        value={vacio ? "" : value}
        placeholder="—"
        onChange={e => {
          const t = e.target.value.trim();
          onChange(t === "" ? null : Math.max(0, Math.trunc(Number(t)) || 0));
        }}
      />
      <button type="button" onClick={() => onChange(vacio ? 1 : value + 1)}>+</button>
    </div>
  );
};

const Field = ({ label, hint, error, children, full }) => (
  <div className={"field" + (full ? " full" : "")} style={full ? { gridColumn: "1 / -1" } : {}}>
    <div className="field-lbl">{label}</div>
    {children}
    {error && <div className="field-err">{error}</div>}
    {hint && !error && <div className="field-hint">{hint}</div>}
  </div>
);

// Input de texto ENLAZADO a estado. Sustituye a los <input> sueltos que no
// guardaban nada. `k` es la clave dentro de `f`.
const T = ({ f, set, k, ph, err, type = "text" }) => (
  <input
    className={"input" + (err ? " err" : "")}
    type={type}
    placeholder={ph}
    value={f[k] ?? ""}
    onChange={e => set(k, e.target.value)}
  />
);

const CheckGrid = ({ options, value, onChange }) => (
  <div className="checkbox-grid">
    {options.map(o => (
      <label className="cbox" key={o}>
        <input type="checkbox" checked={(value || []).includes(o)} onChange={() => {
          const v = value || [];
          onChange(v.includes(o) ? v.filter(x => x !== o) : [...v, o]);
        }}/>
        <span>{o}</span>
      </label>
    ))}
  </div>
);

const TagPick = ({ options, value, onChange, multi }) => (
  <div className="tag-pick">
    {options.map(o => (
      <button
        key={o}
        type="button"
        className={"tag-opt" + ((multi ? (value || []).includes(o) : value === o) ? " active" : "")}
        onClick={() => {
          if (!multi) onChange(o);
          else {
            const v = value || [];
            onChange(v.includes(o) ? v.filter(x => x !== o) : [...v, o]);
          }
        }}
      >
        {o}
      </button>
    ))}
  </div>
);

const PisoFields = ({ f, set }) => (
  <>
    <h4 className="sec-h first">Distribución</h4>
    <div className="intake-grid cols-4">
      <Field label="Planta"><T f={f} set={set} k="planta" ph="Ej: 3"/></Field>
      <Field label="Puerta"><T f={f} set={set} k="puerta" ph="Ej: D"/></Field>
      <Field label="Nº dormitorios"><StepperNum value={f.dormitorios} onChange={v => set("dormitorios", v)}/></Field>
      <Field label="Nº baños"><StepperNum value={f.banos} onChange={v => set("banos", v)}/></Field>
    </div>

    <h4 className="sec-h">Estado y características</h4>
    <div className="intake-grid">
      <Field label="Equipamiento cocina">
        <TagPick options={["Electrodomésticos + amueblada", "Solo electrodomésticos", "Vacía"]} value={f.kitchen} onChange={v => set("kitchen", v)}/>
      </Field>
      <Field label="Estado de conservación">
        <TagPick options={["Buen estado", "A reformar"]} value={f.conservation} onChange={v => set("conservation", v)}/>
      </Field>
      <Field label="Orientación">
        <TagPick options={["Norte", "Sur", "Este", "Oeste"]} value={f.orientation} onChange={v => set("orientation", v)}/>
      </Field>
      <Field label="Ubicación">
        <TagPick options={["Interior", "Exterior"]} value={f.location} onChange={v => set("location", v)}/>
      </Field>
      <Field label="Ascensor">
        <TagPick options={["Sí", "No"]} value={f.elevator} onChange={v => set("elevator", v)}/>
      </Field>
      <Field label="Situación excepcional">
        <select className="select" value={f.situacion || ""} onChange={e => set("situacion", e.target.value)}>
          <option value="">— Sin especificar —</option>
          <option>Ninguna</option><option>Ocupada ilegalmente</option><option>Alquilada con inquilinos</option><option>Nuda propiedad</option>
        </select>
      </Field>
    </div>

    <h4 className="sec-h">Características adicionales</h4>
    <CheckGrid
      options={["Armarios empotrados", "Aire acondicionado", "Terraza", "Balcón", "Trastero", "Piscina", "Jardín", "Adaptado a movilidad reducida"]}
      value={f.features}
      onChange={v => set("features", v)}
    />
  </>
);

const LocalFields = ({ f, set }) => (
  <>
    <h4 className="sec-h first">Distribución</h4>
    <div className="intake-grid cols-4">
      <Field label="Nº de estancias"><StepperNum value={f.estancias} onChange={v => set("estancias", v)}/></Field>
      <Field label="Nº de escaparates"><StepperNum value={f.escaparates} onChange={v => set("escaparates", v)}/></Field>
      <Field label="Plantas del local"><StepperNum value={f.plantasLocal} onChange={v => set("plantasLocal", v)}/></Field>
      <Field label="Nº de baños"><StepperNum value={f.banos} onChange={v => set("banos", v)}/></Field>
    </div>
    <h4 className="sec-h">Equipamiento e instalaciones</h4>
    <CheckGrid
      options={["Calefacción", "Aire acondicionado", "Salida de humos", "Cocina equipada", "Puerta de seguridad", "Alarmas", "Circuito cerrado TV", "Almacén", "Hace esquina", "Tiene oficina"]}
      value={f.features}
      onChange={v => set("features", v)}
    />
  </>
);

const GarajeFields = ({ f, set, err }) => (
  <>
    <h4 className="sec-h first">Capacidad y superficie</h4>
    <div className="intake-grid">
      <Field label="Capacidad de la plaza" full>
        <TagPick options={["Moto", "Coche pequeño", "Coche grande", "Coche y moto", "2 coches o más"]} value={f.capacity} onChange={v => set("capacity", v)}/>
      </Field>
      <Field label="Superficie (m²)" error={err.superficie} hint="Mismo dato que el bloque 2">
        <T f={f} set={set} k="superficie" ph="Ej: 12" err={err.superficie}/>
      </Field>
      <Field label="Precio">
        <TagPick options={["Incluida en el precio", "Se cobra aparte"]} value={f.priceMode} onChange={v => set("priceMode", v)}/>
      </Field>
    </div>
    <h4 className="sec-h">Características</h4>
    <CheckGrid options={["Ascensor", "Seguridad", "Cubierta", "Alarma", "Circuito cerrado", "Puerta automática"]} value={f.features} onChange={v => set("features", v)}/>
  </>
);

const TerrenoFields = ({ f, set, err }) => (
  <>
    <h4 className="sec-h first">Características del terreno</h4>
    <div className="intake-grid">
      <Field label="Tipo de terreno">
        <TagPick options={["Urbano", "Urbanizable", "No urbanizable"]} value={f.terrainType} onChange={v => set("terrainType", v)}/>
      </Field>
      <Field label="Acceso rodado">
        <TagPick options={["Sí", "No"]} value={f.access} onChange={v => set("access", v)}/>
      </Field>
      <Field label="Superficie total (m²)" error={err.superficie} hint="Mismo dato que el bloque 2">
        <T f={f} set={set} k="superficie" ph="Ej: 1.200" err={err.superficie}/>
      </Field>
      <Field label="Distancia al municipio" full>
        <TagPick options={["En núcleo urbano", "Fuera de núcleo urbano"]} value={f.proximity} onChange={v => set("proximity", v)}/>
      </Field>
    </div>
  </>
);

const TraspasoFields = ({ f, set, err }) => (
  <>
    <LocalFields f={f} set={set}/>
    <h4 className="sec-h">Datos del traspaso</h4>
    <div className="intake-grid">
      <Field label="Actividad comercial (hasta 2)" full>
        <T f={f} set={set} k="actividad" ph="Ej: Restauración, Cafetería"/>
      </Field>
      <Field label="Precio de traspaso (€)" error={err.precioTraspaso}><T f={f} set={set} k="precioTraspaso" ph="Ej: 45.000" err={err.precioTraspaso}/></Field>
      <Field label="Alquiler del inmueble (€/mes)" error={err.alquilerInmueble}><T f={f} set={set} k="alquilerInmueble" ph="Ej: 1.200" err={err.alquilerInmueble}/></Field>
      <Field label="Fianza (€)" error={err.fianza}><T f={f} set={set} k="fianza" ph="Ej: 2.400" err={err.fianza}/></Field>
      <Field label="Fin de contrato" full><T f={f} set={set} k="finContrato" type="date"/></Field>
    </div>
  </>
);

const DefaultFields = ({ f, set, type, err }) => (
  <>
    <h4 className="sec-h first">{type} — características</h4>
    <div className="intake-grid cols-2">
      <Field label="Superficie (m²)" error={err.superficie} hint="Mismo dato que el bloque 2">
        <T f={f} set={set} k="superficie" ph="Ej: 95" err={err.superficie}/>
      </Field>
      <Field label="Notas"><T f={f} set={set} k="notasTipo" ph="Detalles relevantes"/></Field>
    </div>
  </>
);

/**
 * Deshace `construirPayload`: fila de la base -> estado del formulario.
 *
 * Vive al lado de `construirPayload` a proposito. Son inversas la una de la
 * otra y hay que tocarlas a la vez: si se añade un campo arriba y no aqui,
 * editar un inmueble lo borraria en silencio.
 */
const desdeFila = (r) => {
  const c = r.caracteristicas || {};
  const est = r.estados || [];
  const txt = (v) => (v === null || v === undefined ? "" : String(v));
  return {
    type: (TYPES.find((t) => t.db === r.tipo) || TYPES[0]).key,
    f: {
      calle: txt(r.direccion), numero: txt(r.numero), municipio: txt(r.municipio),
      cp: txt(r.cp), refCatastral: txt(r.ref_catastral), superficie: txt(r.superficie),
      planta: txt(r.planta), puerta: txt(r.puerta),
      dormitorios: txt(r.dormitorios), banos: txt(r.banos),
      precioVenta: txt(r.precio_venta_actual), objetivoVenta: txt(r.precio_venta_objetivo),
      claseEnergetica: r.clase_energetica || "", claseEmisiones: r.emisiones_clase || "",
      captadorId: r.captador_id || "", comercializadorId: r.comercializador_id || "",
      opVenta: est.includes("En venta"), opAlquiler: est.includes("En alquiler"),
      // lo que vive en el jsonb `caracteristicas`
      kitchen: c.cocina, conservation: c.conservacion, orientation: c.orientacion,
      location: c.ubicacion, elevator: c.ascensor, situacion: c.situacion_excepcional,
      casaType: c.tipologia_casa, capacity: c.capacidad_plaza, priceMode: c.modo_precio_plaza,
      terrainType: c.tipo_terreno, access: c.acceso_rodado, proximity: c.proximidad,
      estancias: c.estancias, escaparates: c.escaparates, plantasLocal: c.plantas_local,
      actividad: txt(c.actividad_comercial), precioTraspaso: txt(c.precio_traspaso),
      alquilerInmueble: txt(c.alquiler_inmueble_mes), fianza: txt(c.fianza),
      finContrato: txt(c.fin_contrato), gastosComunidad: txt(c.gastos_comunidad_mes),
      alquilerMes: txt(c.alquiler_mes), rentType: c.tipo_alquiler,
      tenants: c.inquilinos_max, pets: c.mascotas,
      consumo: txt(c.consumo_kwh_m2_ano), emisiones: txt(c.emisiones_kg_co2_m2_ano),
      visibility: c.visibilidad_notas, notasPrivadas: txt(c.notas_privadas),
      notasTipo: txt(c.notas_tipo), features: c.extras || [],
    },
  };
};

/**
 * Alta Y edicion de inmuebles, el mismo formulario.
 *
 * Con `inmuebleId` edita; sin el, da de alta. Es el mismo formulario a
 * proposito: tiene todos los campos, todas las validaciones y toda la logica
 * condicional por tipo. Un segundo formulario solo para editar seria dos
 * sitios donde arreglar cada cosa, y acabarian divergiendo.
 */
const AltaInmueble = ({ onCancel, onSave, inmuebleId = null }) => {
  const { Icons, Card } = window;
  const editando = !!inmuebleId;
  const [cargando, setCargando] = React.useState(editando);
  const [type, setType] = React.useState("PISO");
  // `municipio` NACE VACÍO: precargar "Jaén" era afirmar la ubicación del inmueble
  // por el usuario. Es obligatorio y `validar()` lo exige, así que no se envía vacío:
  // se bloquea el guardado con el error del campo.
  const [f, setF] = React.useState({ opVenta: true, opAlquiler: false });
  const [err, setErr] = React.useState({});
  const [banner, setBanner] = React.useState(null);   // {tono, texto}
  const [guardando, setGuardando] = React.useState(false);
  const [ref, setRef] = React.useState(null);
  const set = (k, v) => setF(d => ({ ...d, [k]: v }));

  // En edicion, el formulario nace vacio y se rellena con la fila real. Se
  // pide cruda y no se saca de DATA: DATA viene mapeada para pintar.
  React.useEffect(() => {
    if (!editando) return;
    let vivo = true;
    (async () => {
      try {
        const fila = await window.RevinSupabase.cargarInmuebleCrudo(inmuebleId);
        if (!vivo) return;
        const { type: t, f: campos } = desdeFila(fila);
        setType(t); setF(campos); setRef(fila.ref);
      } catch (e) {
        if (vivo) setBanner({ tono: "err", texto: "No se ha podido cargar el inmueble: " + ((e && e.message) || e) });
      } finally {
        if (vivo) setCargando(false);
      }
    })();
    return () => { vivo = false; };
  }, [inmuebleId, editando]);

  const enVivo = !!(window.RevinData && window.RevinData.isLive);

  // Referencia sugerida del año en curso (solo lectura). Se recalcula en el
  // insert, así que si alguien se la lleva mientras rellenas, no se pierde nada.
  React.useEffect(() => {
    if (!enVivo || !window.RevinSupabase) return;
    if (editando) return;   // editando, la referencia es la que ya tiene
    let vivo = true;
    window.RevinSupabase.siguienteRef()
      .then(r => { if (vivo) setRef(r); })
      .catch(() => { if (vivo) setRef(null); });
    return () => { vivo = false; };
  }, [enVivo]);

  // Equipo REAL desde `usuarios` (antes: nombres inventados hardcodeados).
  const equipo = (window.DATA?.TEAM || []).filter(m => m.estado !== "inactivo" && m.supabase?.id);

  const validar = () => {
    const e = {};
    if ((f.calle || "").trim().length < 3) e.calle = "Indica la calle (mínimo 3 caracteres).";
    if (!(f.municipio || "").trim()) e.municipio = "El municipio es obligatorio.";
    if (!f.opVenta && !f.opAlquiler) e.operacion = "Marca al menos una operación: venta o alquiler.";

    const numérico = (k, etiqueta, { min = 0 } = {}) => {
      if ((f[k] ?? "") === "") return;
      const n = numOrNull(f[k]);
      if (Number.isNaN(n)) e[k] = `${etiqueta}: introduce un número válido.`;
      else if (n < min) e[k] = `${etiqueta}: debe ser mayor que ${min}.`;
    };
    numérico("superficie", "Superficie", { min: 1 });
    numérico("precioVenta", "Precio de venta");
    numérico("objetivoVenta", "Objetivo de venta");
    numérico("gastosComunidad", "Gastos de comunidad");
    numérico("alquilerMes", "Alquiler");
    numérico("precioTraspaso", "Precio de traspaso");
    numérico("alquilerInmueble", "Alquiler del inmueble");
    numérico("fianza", "Fianza");
    numérico("consumo", "Consumo");
    numérico("emisiones", "Emisiones");

    if ((f.cp || "").trim() && !/^\d{5}$/.test(f.cp.trim())) e.cp = "El código postal son 5 dígitos.";
    if ((f.refCatastral || "").trim() && f.refCatastral.trim().length !== 20)
      e.refCatastral = "La referencia catastral son 20 caracteres.";
    return e;
  };

  const construirPayload = () => {
    const estados = [];
    if (f.opVenta) estados.push("En venta");
    if (f.opAlquiler) estados.push("En alquiler");

    const esPisoT = ["PISO", "CASA", "CHALET"].includes(type);
    const esLocalT = ["LOCAL", "NAVE", "TRASPASO"].includes(type);

    // Todo lo condicional por tipo va al jsonb: evita una columna por tipo.
    const caracteristicas = {};
    const guardaSi = (k, v) => { if (v !== null && v !== undefined && v !== "") caracteristicas[k] = v; };
    // B1 — Solo se guarda lo que el usuario ha elegido. Ni un valor por defecto:
    // `guardaSi` omite null/undefined/"" y la clave no llega a existir en el jsonb.
    // El comentario anterior decía que se guardaba «lo que se ve en pantalla», y
    // además de ser una afirmación que nadie había hecho, ni siquiera era cierto:
    // estancias/escaparates/plantas_local se pintaban a 1 y NO se guardaban.
    if (esPisoT) {
      guardaSi("cocina", f.kitchen);
      guardaSi("conservacion", f.conservation);
      guardaSi("orientacion", f.orientation);
      guardaSi("ubicacion", f.location);
      guardaSi("ascensor", f.elevator);
      guardaSi("situacion_excepcional", f.situacion);
      if (type === "CASA" || type === "CHALET") guardaSi("tipologia_casa", f.casaType);
    }
    if (type === "GARAJE") {
      guardaSi("capacidad_plaza", f.capacity);
      guardaSi("modo_precio_plaza", f.priceMode);
    }
    if (type === "TERRENO" || type === "PARCELA") {
      guardaSi("tipo_terreno", f.terrainType);
      guardaSi("acceso_rodado", f.access);
      guardaSi("proximidad", f.proximity);
    }
    guardaSi("estancias", f.estancias); guardaSi("escaparates", f.escaparates);
    guardaSi("plantas_local", f.plantasLocal); guardaSi("actividad_comercial", txtOrNull(f.actividad));
    guardaSi("precio_traspaso", numOrNull(f.precioTraspaso));
    guardaSi("alquiler_inmueble_mes", numOrNull(f.alquilerInmueble));
    guardaSi("fianza", numOrNull(f.fianza)); guardaSi("fin_contrato", txtOrNull(f.finContrato));
    guardaSi("gastos_comunidad_mes", numOrNull(f.gastosComunidad));
    if (f.opAlquiler) {
      guardaSi("alquiler_mes", numOrNull(f.alquilerMes));
      guardaSi("tipo_alquiler", f.rentType);
      guardaSi("inquilinos_max", f.tenants);
      guardaSi("mascotas", f.pets);
    }
    guardaSi("consumo_kwh_m2_ano", numOrNull(f.consumo));
    guardaSi("emisiones_kg_co2_m2_ano", numOrNull(f.emisiones));
    // Se queda con valor por defecto A PROPÓSITO: no es un dato del inmueble, es un
    // ajuste de quién ve las notas. La regla 10 protege lo que el usuario podría
    // creerse como hecho; esto no lo es.
    guardaSi("visibilidad_notas", f.visibility || "Mi equipo");
    guardaSi("notas_privadas", txtOrNull(f.notasPrivadas));
    guardaSi("notas_tipo", txtOrNull(f.notasTipo));
    if ((f.features || []).length) caracteristicas.extras = f.features;

    const esPiso = esPisoT;
    const esLocal = esLocalT;

    return {
      tipo: TYPES.find(t => t.key === type).db,
      direccion: f.calle.trim(),
      numero: txtOrNull(f.numero),
      municipio: (f.municipio || "").trim(),
      cp: txtOrNull(f.cp),
      ref_catastral: txtOrNull(f.refCatastral),
      superficie: numOrNull(f.superficie),
      planta: esPiso ? txtOrNull(f.planta) : null,
      puerta: esPiso ? txtOrNull(f.puerta) : null,
      dormitorios: esPiso ? intOrNull(f.dormitorios) : null,
      banos: (esPiso || esLocal) ? intOrNull(f.banos) : null,
      precio_venta_actual: f.opVenta ? numOrNull(f.precioVenta) : null,
      precio_venta_objetivo: f.opVenta ? numOrNull(f.objetivoVenta) : null,
      // El certificado energético es un DOCUMENTO LEGAL emitido por un técnico.
      // Sin él, el hueco: null. «Exento» y «en trámite» son estados reales del
      // certificado y siguen elegibles; «no lo sé» no es una clase energética.
      clase_energetica: f.claseEnergetica || null,
      emisiones_clase: f.claseEmisiones || null,
      captador_id: f.captadorId || null,
      comercializador_id: f.comercializadorId || null,
      estados,
      estado_texto: estados.join(", ") || null,
      caracteristicas,
    };
  };

  const guardar = async () => {
    setBanner(null);
    const e = validar();
    setErr(e);
    const nErrores = Object.keys(e).length;
    if (nErrores) {
      setBanner({ tono: "err", texto: `Revisa ${nErrores} ${nErrores === 1 ? "campo" : "campos"} antes de guardar.` });
      const primero = document.querySelector(".input.err, .select.err, .field-err");
      if (primero) primero.scrollIntoView({ behavior: "smooth", block: "center" });
      return;
    }
    if (!enVivo) {
      setBanner({ tono: "warn", texto: editando
        ? "Conéctate a Supabase para editar. En modo de prueba no se guarda nada."
        : "Conéctate a Supabase para dar de alta. En modo de prueba no se guarda nada." });
      return;
    }
    setGuardando(true);
    try {
      const creado = editando
        ? await window.RevinSupabase.actualizarInmueble(inmuebleId, construirPayload())
        : await window.RevinSupabase.crearInmueble({ ...construirPayload(), ref });
      // onSave ANTES de recargar: la recarga remonta el árbol y se llevaría por
      // delante cualquier estado que fijásemos después (ver _postAlta en App.jsx).
      onSave && onSave(creado);
      if (window.RevinData?.reload) await window.RevinData.reload();
    } catch (ex) {
      const msg = ex?.message || String(ex);
      setBanner({
        tono: "err",
        texto: /duplicate key|23505/i.test(msg)
          ? "Ya existe un inmueble con esa referencia. Vuelve a intentarlo: se asignará la siguiente libre."
          : `No se pudo guardar: ${msg}`,
      });
      setGuardando(false);
    }
  };

  const errBloque = (k) => err[k];

  return (
    <>
      <div className="page-h">
        <div>
          <button className="btn ghost xs" onClick={onCancel} style={{ paddingLeft: 0, marginBottom: 6 }}>
            <Icons.ChevronLeft/> {editando ? "Volver sin guardar" : "Cancelar alta"}
          </button>
          <h1>{editando ? `EDITAR · ${ref || ""}` : "NUEVO INMUEBLE"}</h1>
          <div className="sub">
            {editando
              ? <>Cambia lo que haga falta y pulsa <b>Guardar cambios</b>. Lo que no toques se queda como está.</>
              : <>El formulario se adapta al tipo seleccionado — sigue cada bloque y al final pulsa <b>Crear ficha</b>.</>}
          </div>
        </div>
        <div className="actions">
          <button className="btn secondary" onClick={onCancel} disabled={guardando}>Cancelar</button>
          <button className="btn primary" onClick={guardar} disabled={guardando || cargando}>
            {editando ? <Icons.Check/> : <Icons.Plus/>}
            {guardando ? "Guardando…" : editando ? "Guardar cambios" : "Crear ficha"}
          </button>
        </div>
      </div>

      {cargando && (
        <div className="alta-banner">
          <Icons.Alert/><span>Cargando la ficha del inmueble…</span>
        </div>
      )}

      {banner && (
        <div className={"alta-banner " + banner.tono}>
          <Icons.Alert/><span>{banner.texto}</span>
        </div>
      )}
      {!enVivo && !banner && (
        <div className="alta-banner warn">
          <Icons.Alert/><span><b>Sin conexión</b> — conéctate a Supabase para poder {editando ? "editar" : "dar de alta"}. Ahora mismo no se guardaría nada.</span>
        </div>
      )}

      <Card title="1 · Tipo de inmueble" b={false}>
        <div style={{ padding: 16, display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 8 }}>
          {TYPES.map(t => (
            <button
              key={t.key}
              type="button"
              className={"tag-opt" + (type === t.key ? " active" : "")}
              onClick={() => setType(t.key)}
              style={{ padding: "10px 8px", textAlign: "center", flexDirection: "column", display: "flex", justifyContent: "center", alignItems: "center", gap: 4, minHeight: 60 }}
            >
              <div style={{ fontWeight: 700, fontSize: 12 }}>{t.label}</div>
            </button>
          ))}
        </div>
      </Card>

      <Card title="2 · Datos generales" b={false} style={{ marginTop: 16 }}>
        <div style={{ padding: 16 }}>
          <div className="intake-grid">
            <Field label="Calle *" error={err.calle}><T f={f} set={set} k="calle" ph="Ej: Calle Real" err={err.calle}/></Field>
            <Field label="Número"><T f={f} set={set} k="numero" ph="Ej: 24"/></Field>
            <Field label="Municipio *" error={err.municipio}><T f={f} set={set} k="municipio" ph="Jaén" err={err.municipio}/></Field>
            <Field label="Código postal" error={err.cp}><T f={f} set={set} k="cp" ph="23001" err={err.cp}/></Field>
            <Field label="Referencia catastral" error={err.refCatastral}><T f={f} set={set} k="refCatastral" ph="0000000XX0000X0000XX" err={err.refCatastral}/></Field>
            <Field label="Superficie total (m²)" error={err.superficie}><T f={f} set={set} k="superficie" ph="92" err={err.superficie}/></Field>
          </div>
        </div>
      </Card>

      <Card title={`3 · Características específicas · ${type}`} right={<Pill tone="brand">Lógica condicional</Pill>} b={false} style={{ marginTop: 16 }}>
        <div style={{ padding: 16 }}>
          {["PISO", "CASA", "CHALET"].includes(type) ? <PisoFields f={f} set={set}/> : null}
          {type === "LOCAL" || type === "NAVE" ? <LocalFields f={f} set={set}/> : null}
          {type === "TRASPASO" ? <TraspasoFields f={f} set={set} err={err}/> : null}
          {type === "GARAJE" ? <GarajeFields f={f} set={set} err={err}/> : null}
          {type === "TERRENO" || type === "PARCELA" ? <TerrenoFields f={f} set={set} err={err}/> : null}
          {["TRASTERO", "OFICINA", "EDIFICIO"].includes(type) ? <DefaultFields f={f} set={set} type={type} err={err}/> : null}

          {(type === "CASA" || type === "CHALET") && (
            <>
              <h4 className="sec-h">Tipología de casa</h4>
              <TagPick options={["Chalet adosado", "Chalet pareado", "Chalet independiente"]} value={f.casaType} onChange={v => set("casaType", v)}/>
            </>
          )}
        </div>
      </Card>

      <Card title="4 · Operación y precio" b={false} style={{ marginTop: 16 }}>
        <div style={{ padding: 16 }}>
          <div style={{ display: "flex", gap: 8, marginBottom: 14 }}>
            <label className="cbox" style={{ padding: "8px 14px", border: "1px solid var(--border-2)", borderRadius: 4, background: f.opVenta ? "var(--red-50)" : "var(--bg-surface)" }}>
              <input type="checkbox" checked={!!f.opVenta} onChange={e => set("opVenta", e.target.checked)}/>
              <b>Venta</b>
            </label>
            <label className="cbox" style={{ padding: "8px 14px", border: "1px solid var(--border-2)", borderRadius: 4, background: f.opAlquiler ? "var(--red-50)" : "var(--bg-surface)" }}>
              <input type="checkbox" checked={!!f.opAlquiler} onChange={e => set("opAlquiler", e.target.checked)}/>
              <b>Alquiler</b>
            </label>
          </div>
          {errBloque("operacion") && <div className="field-err" style={{ marginBottom: 12 }}>{err.operacion}</div>}

          {f.opVenta && (
            <div className="intake-grid" style={{ marginBottom: 14 }}>
              <Field label="Precio de venta (€)" error={err.precioVenta}><T f={f} set={set} k="precioVenta" ph="145.000" err={err.precioVenta}/></Field>
              <Field label="Gastos de comunidad (€/mes)" error={err.gastosComunidad}><T f={f} set={set} k="gastosComunidad" ph="35" err={err.gastosComunidad}/></Field>
              <Field label="Objetivo de venta (€)" error={err.objetivoVenta}><T f={f} set={set} k="objetivoVenta" ph="195.000" err={err.objetivoVenta}/></Field>
            </div>
          )}
          {f.opAlquiler && (
            <div className="intake-grid">
              <Field label="Alquiler (€/mes)" error={err.alquilerMes}><T f={f} set={set} k="alquilerMes" ph="700" err={err.alquilerMes}/></Field>
              <Field label="Tipo">
                <TagPick options={["Residencial", "Temporada", "Vacacional"]} value={f.rentType} onChange={v => set("rentType", v)}/>
              </Field>
              <Field label="Inquilinos máx."><StepperNum value={f.tenants} onChange={v => set("tenants", v)}/></Field>
              <Field label="Mascotas">
                <TagPick options={["Sí", "No"]} value={f.pets} onChange={v => set("pets", v)}/>
              </Field>
            </div>
          )}
        </div>
      </Card>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, marginTop: 16 }}>
        <Card title="5 · Eficiencia energética" b={false}>
          <div style={{ padding: 16 }}>
            <div className="intake-grid cols-2">
              <Field label="Clase energética">
                <select className="select" value={f.claseEnergetica || ""} onChange={e => set("claseEnergetica", e.target.value)}>
                  <option value="">— Sin especificar —</option>
                  {CLASES_ENERG.map(c => <option key={c.v} value={c.v}>{c.l}</option>)}
                </select>
              </Field>
              <Field label="Consumo (kWh/m²·año)" error={err.consumo}><T f={f} set={set} k="consumo" ph="120" err={err.consumo}/></Field>
              <Field label="Clase de emisiones">
                <select className="select" value={f.claseEmisiones || ""} onChange={e => set("claseEmisiones", e.target.value)}>
                  <option value="">— Sin especificar —</option>
                  {CLASES_ENERG.map(c => <option key={c.v} value={c.v}>{c.l}</option>)}
                </select>
              </Field>
              <Field label="Emisiones (kg CO₂/m²·año)" error={err.emisiones}><T f={f} set={set} k="emisiones" ph="28" err={err.emisiones}/></Field>
            </div>
          </div>
        </Card>

        <Card title="6 · Datos internos REVIN" right={<Pill tone="danger">Privado</Pill>} b={false}>
          <div style={{ padding: 16 }}>
            <div className="intake-grid cols-2">
              <Field label="Agente captador">
                <select className="select" value={f.captadorId || ""} onChange={e => set("captadorId", e.target.value)}>
                  <option value="">— Sin asignar —</option>
                  {equipo.map(m => <option key={m.supabase.id} value={m.supabase.id}>{m.name}</option>)}
                </select>
              </Field>
              <Field label="Agente comercializador">
                <select className="select" value={f.comercializadorId || ""} onChange={e => set("comercializadorId", e.target.value)}>
                  <option value="">— Sin asignar —</option>
                  {equipo.map(m => <option key={m.supabase.id} value={m.supabase.id}>{m.name}</option>)}
                </select>
              </Field>
              <Field label="Referencia interna" hint="Se asigna sola: año + secuencia anual">
                <input className="input mono" value={ref || (enVivo ? "Calculando…" : "—")} readOnly disabled/>
              </Field>
              <Field label="Visibilidad de notas">
                <TagPick options={["Solo yo", "Mi equipo", "Toda REVIN"]} value={f.visibility || "Mi equipo"} onChange={v => set("visibility", v)}/>
              </Field>
              <Field label="Notas privadas" full>
                <textarea className="input" placeholder="Comentarios internos del comercial sobre el inmueble..."
                  value={f.notasPrivadas || ""} onChange={e => set("notasPrivadas", e.target.value)}/>
              </Field>
            </div>
          </div>
        </Card>
      </div>

      <Card
        title="7 · Multimedia"
        right={<Pill tone="neutral">Próximamente</Pill>}
        b={false}
        style={{ marginTop: 16, marginBottom: 24 }}
      >
        <div style={{ padding: "10px 16px 0", fontSize: 12, color: "var(--fg-3)" }}>
          La subida de fotos aún no está conectada a Supabase Storage. El bloque queda visible
          como pendiente, pero deshabilitado para no dar por guardado algo que no lo está.
        </div>
        <div style={{ padding: 16 }} className="bloque-off" aria-disabled="true">
          <div className="dropzone">
            <Icons.Upload size={32}/>
            <div>Arrastra fotos aquí o <b style={{ color: "var(--revin-red)" }}>haz clic para subirlas</b></div>
            <div style={{ fontSize: 11, color: "var(--fg-3)", marginTop: 4 }}>JPG, PNG · máx. 5 MB por foto · mínimo 8 fotos</div>
          </div>
        </div>
      </Card>
    </>
  );
};

window.AltaInmueble = AltaInmueble;
