// =========================================================================
// FIRMA DE PARTE DE VISITA — captura con el dedo + sello temporal del servidor
// =========================================================================
// Invariante (30_firma_visitas.sql): FIRMA = INSERT, jamás UPDATE. El sello es
// `created_at` (server now()). Bloque firmado inmutable; notas editables aparte.
// Trazo VECTORIAL en el jsonb (sin PNG, sin Storage). Snapshot OBLIGATORIO.

// El texto de protección de datos lo redacta la gestoría de REVIN. Se deja como
// HUECO LITERAL a propósito: no se inventa contenido jurídico.
const TEXTO_LOPD = "{{TEXTO_LOPD}}";

// Texto ÍNTEGRO que ve y firma el visitante. Lo que se muestra ES lo que se
// guarda (misma cadena): editar la fila luego no puede cambiar lo firmado.
function construirSnapshotVisita({ inmueble, agente, nombre, dni, fechaMostrada }) {
  const dir = [inmueble.addr, inmueble.town].filter(Boolean).join(", ");
  return [
    "PARTE DE VISITA — REVIN",
    "",
    `Inmueble: ${dir}${inmueble.ref ? ` (Ref. ${inmueble.ref})` : ""}`,
    `Fecha y hora mostradas: ${fechaMostrada}`,
    `Agente REVIN: ${agente || "—"}`,
    `Firmante: ${(nombre || "—")}${dni ? ` · DNI/NIE ${dni}` : ""}`,
    "",
    "El firmante declara haber visitado el inmueble arriba indicado acompañado por",
    "el agente de REVIN, y que los datos declarados son ciertos.",
    "",
    TEXTO_LOPD,
    "",
    "(El sello temporal legal de esta firma es la fecha de registro en el servidor.)",
  ].join("\n");
}

// ---- Pad de firma: dibujo por pointer events -> trazos {x,y} vectoriales ----
const SignaturePad = ({ onChange, height = 190 }) => {
  const W = 560, H = height;                     // resolución interna fija
  const canvasRef = React.useRef(null);
  const strokes = React.useRef([]);              // [[{x,y}...]...]
  const cur = React.useRef(null);
  const drawing = React.useRef(false);
  const [vacio, setVacio] = React.useState(true);

  const g = () => canvasRef.current.getContext("2d");
  const redraw = () => {
    const c = canvasRef.current; if (!c) return;
    const ctx = g();
    ctx.clearRect(0, 0, c.width, c.height);
    ctx.strokeStyle = "#161A1D"; ctx.lineWidth = 2.4; ctx.lineJoin = "round"; ctx.lineCap = "round";
    const all = cur.current ? strokes.current.concat([cur.current]) : strokes.current;
    all.forEach(st => {
      if (st.length < 1) return;
      ctx.beginPath();
      st.forEach((p, i) => (i ? ctx.lineTo(p.x, p.y) : ctx.moveTo(p.x, p.y)));
      ctx.stroke();
    });
  };
  const pos = (e) => {
    const c = canvasRef.current, r = c.getBoundingClientRect();
    const sx = c.width / r.width, sy = c.height / r.height;
    return { x: Math.round((e.clientX - r.left) * sx), y: Math.round((e.clientY - r.top) * sy) };
  };
  const down = (e) => { e.preventDefault(); e.target.setPointerCapture?.(e.pointerId); drawing.current = true; cur.current = [pos(e)]; redraw(); };
  const move = (e) => { if (!drawing.current) return; e.preventDefault(); cur.current.push(pos(e)); redraw(); };
  const up = () => {
    if (!drawing.current) return;
    drawing.current = false;
    if (cur.current && cur.current.length > 1) strokes.current.push(cur.current);
    cur.current = null; redraw();
    const data = strokes.current.map(s => s.map(p => ({ x: p.x, y: p.y })));
    setVacio(data.length === 0);
    onChange({ tipo: "strokes", w: W, h: H, data });
  };
  const clear = () => { strokes.current = []; cur.current = null; redraw(); setVacio(true); onChange({ tipo: "strokes", w: W, h: H, data: [] }); };

  React.useEffect(() => { redraw(); }, []);

  return (
    <div>
      <canvas
        ref={canvasRef} width={W} height={H}
        onPointerDown={down} onPointerMove={move} onPointerUp={up} onPointerLeave={up} onPointerCancel={up}
        style={{ touchAction: "none", width: "100%", maxWidth: W, height: "auto", aspectRatio: `${W} / ${H}`,
                 background: "#fff", border: "1px dashed var(--border-2)", borderRadius: 6, cursor: "crosshair", display: "block" }}
      />
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 6 }}>
        <span style={{ fontSize: 11, color: "var(--fg-3)" }}>{vacio ? "Firme con el dedo o el ratón dentro del recuadro." : "Firma capturada."}</span>
        <button type="button" className="btn ghost xs" onClick={clear}>Borrar firma</button>
      </div>
    </div>
  );
};

// ---- Replay read-only de un trazo firmado (para el parte inmutable) ----
const FirmaSVG = ({ trazo, maxWidth = 240 }) => {
  if (!trazo || !Array.isArray(trazo.data) || trazo.data.length === 0) return <span style={{ color: "var(--fg-4)", fontSize: 12 }}>—</span>;
  const w = trazo.w || 560, h = trazo.h || 190;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} style={{ width: "100%", maxWidth, height: "auto", background: "#fff", border: "1px solid var(--border-1)", borderRadius: 4 }}>
      {trazo.data.map((st, i) => (
        <path key={i} d={"M " + st.map(p => `${p.x} ${p.y}`).join(" L ")} fill="none" stroke="#161A1D" strokeWidth={2.4} strokeLinejoin="round" strokeLinecap="round" />
      ))}
    </svg>
  );
};

// =========================================================================
// Modal de firma
// =========================================================================
const FirmarParteVisitaModal = ({ inmueble, onClose, onSaved }) => {
  const { Icons, DATA } = window;
  const RS = window.RevinSupabase;
  const isLive = !!(window.RevinData && window.RevinData.isLive);
  const agente = (DATA.USER && DATA.USER.name) || "—";

  // fecha mostrada: se fija UNA vez al abrir → snapshot estable (shown = saved).
  const [fechaMostrada] = React.useState(() => new Date().toLocaleString("es-ES"));

  // --- Firmante: buscar existente o crear al vuelo (camino principal) ---
  const contactos = (DATA.CLIENTS || []);
  const [q, setQ] = React.useState("");
  const [clienteId, setClienteId] = React.useState(null);   // existente
  const [modoNuevo, setModoNuevo] = React.useState(false);
  const [nombre, setNombre] = React.useState("");           // nombre declarado
  const [telefono, setTelefono] = React.useState("");
  const [dni, setDni] = React.useState("");                 // DNI declarado

  const resultados = q.trim().length >= 2
    ? contactos.filter(c => {
        const s = q.toLowerCase();
        return (c.displayName || c.name || "").toLowerCase().includes(s) || (c.phone || "").toLowerCase().includes(s);
      }).slice(0, 6)
    : [];

  const elegir = (c) => {
    setClienteId(c.id); setModoNuevo(false);
    setNombre(c.displayName || c.name || ""); setTelefono(c.phone || "");
    setDni(c.supabase?.dni_cif || "");
    setQ(c.displayName || c.name || "");
  };
  const nuevo = () => { setModoNuevo(true); setClienteId(null); setNombre(q.trim()); };

  // --- Geolocalización best-effort (no bloquea) ---
  const [geo, setGeo] = React.useState(null);
  const [geoEstado, setGeoEstado] = React.useState("idle"); // idle|pidiendo|ok|denegada|nd
  const pedirGeo = () => {
    if (!navigator.geolocation) { setGeoEstado("nd"); return; }
    setGeoEstado("pidiendo");
    navigator.geolocation.getCurrentPosition(
      (p) => { setGeo({ lat: p.coords.latitude, lng: p.coords.longitude, accuracy: p.coords.accuracy }); setGeoEstado("ok"); },
      () => { setGeo(null); setGeoEstado("denegada"); },
      { enableHighAccuracy: true, timeout: 8000, maximumAge: 60000 }
    );
  };

  // --- Firma (trazo) ---
  const [trazo, setTrazo] = React.useState({ tipo: "strokes", w: 560, h: 190, data: [] });
  const [writeBack, setWriteBack] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [aviso, setAviso] = React.useState(null);   // aviso de conflicto de DNI

  const snapshot = construirSnapshotVisita({ inmueble, agente, nombre, dni, fechaMostrada });
  const hayFirmante = !!(clienteId || (modoNuevo && nombre.trim()));
  const hayTrazo = trazo.data.length > 0;

  const firmar = async () => {
    setError(null);
    if (!hayFirmante) { setError("Selecciona o crea el firmante."); return; }
    if (!hayTrazo) { setError("Falta la firma."); return; }
    setBusy(true);
    try {
      // 1) resolver cliente_id (crear al vuelo si es nuevo)
      let cid = clienteId;
      if (!cid && modoNuevo) {
        const c = await RS.crearCliente({ nombre: nombre.trim(), tipo: "comprador", telefono: telefono.trim() || null });
        cid = c.id;
      }
      if (!cid) throw new Error("No se pudo resolver el firmante.");

      // 2) construir firma jsonb y FIRMAR (INSERT; sello = created_at servidor)
      const firma = {
        trazo,
        snapshot,
        firmante: { nombre_declarado: nombre.trim() || null, dni_declarado: dni.trim() || null },
        geo: geo || null,
      };
      await RS.firmarVisita({ inmueble_id: inmueble._uid, cliente_id: cid, firma });

      // 3) write-back opcional a la ficha del cliente (sin pisar DNI distinto)
      if (writeBack && (dni.trim() || telefono.trim())) {
        const r = await RS.completarDatosCliente(cid, { dni_cif: dni.trim() || null, telefono: telefono.trim() || null });
        if (r.conflictoDni) {
          setAviso(`El cliente ya tiene un DNI distinto (${r.dniExistente}). Se conservó el suyo; el declarado quedó en el parte firmado.`);
        }
      }

      // refresco reload-less (no expulsa la ficha)
      const data = await RS.loadDataFromSupabase();
      window.DATA = data;
      onSaved && onSaved();
      if (!aviso) onClose();
    } catch (e) {
      console.error(e);
      setError(e.message || "No se pudo registrar la firma.");
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="sb-login-back" onClick={busy ? undefined : onClose}>
      <form className="sb-login" style={{ width: "min(680px, 96vw)", maxHeight: "92vh", overflowY: "auto" }}
            onClick={(e) => e.stopPropagation()} onSubmit={(e) => { e.preventDefault(); firmar(); }}>
        <div className="sb-login-h">
          <div>
            <div className="eyebrow red">Parte de visita</div>
            <h2 className="sb-login-title" style={{ marginTop: 6, fontSize: 20 }}>Firmar visita</h2>
          </div>
          <button type="button" className="btn ghost xs" onClick={onClose}><Icons.X/></button>
        </div>

        <p className="sb-login-sub" style={{ marginBottom: 12 }}>
          {[inmueble.addr, inmueble.town].filter(Boolean).join(", ")}{inmueble.ref ? ` · Ref. ${inmueble.ref}` : ""}
        </p>

        {/* 1 · FIRMANTE */}
        <div className="field">
          <label className="field-lbl">Firmante *</label>
          <input className="input" value={q} onChange={(e) => { setQ(e.target.value); setClienteId(null); setModoNuevo(false); }}
                 placeholder="Busca por nombre o teléfono…" autoFocus/>
          {resultados.length > 0 && !clienteId && (
            <div style={{ border: "1px solid var(--border-1)", borderRadius: 6, marginTop: 4, maxHeight: 150, overflowY: "auto" }}>
              {resultados.map(c => (
                <div key={c.id} onClick={() => elegir(c)} style={{ padding: "8px 10px", cursor: "pointer", fontSize: 13, borderBottom: "1px solid var(--border-1)" }}>
                  <b>{c.displayName || c.name}</b>{c.phone ? <span style={{ color: "var(--fg-3)", fontFamily: "var(--font-mono)", marginLeft: 8, fontSize: 11 }}>{c.phone}</span> : null}
                </div>
              ))}
            </div>
          )}
          {q.trim().length >= 2 && !clienteId && !modoNuevo && (
            <button type="button" className="btn ghost xs" style={{ marginTop: 6 }} onClick={nuevo}>
              <Icons.Plus/> Crear «{q.trim()}» como nuevo contacto
            </button>
          )}
          {clienteId && <div style={{ fontSize: 12, color: "var(--success)", marginTop: 6 }}>✓ Contacto existente seleccionado.</div>}
          {modoNuevo && <div style={{ fontSize: 12, color: "var(--info-fg, var(--fg-2))", marginTop: 6 }}>Se creará como contacto nuevo al firmar.</div>}
        </div>

        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <div className="field">
            <label className="field-lbl">Nombre declarado</label>
            <input className="input" value={nombre} onChange={(e) => setNombre(e.target.value)} placeholder="Nombre y apellidos"/>
          </div>
          <div className="field">
            <label className="field-lbl">DNI/NIE declarado</label>
            <input className="input" value={dni} onChange={(e) => setDni(e.target.value)} placeholder="00000000X"/>
          </div>
        </div>
        {modoNuevo && (
          <div className="field">
            <label className="field-lbl">Teléfono</label>
            <input className="input" value={telefono} onChange={(e) => setTelefono(e.target.value)} placeholder="6XX XXX XXX"/>
          </div>
        )}

        {/* 2 · SNAPSHOT (lo que se firma) */}
        <div className="field">
          <label className="field-lbl">Texto que se firma</label>
          <pre style={{ whiteSpace: "pre-wrap", fontFamily: "var(--font-body, inherit)", fontSize: 12, lineHeight: 1.5,
                        background: "var(--bg-1, #f6f6f6)", border: "1px solid var(--border-1)", borderRadius: 6, padding: 12, margin: 0, color: "var(--fg-1)" }}>
            {snapshot}
          </pre>
        </div>

        {/* 3 · FIRMA */}
        <div className="field">
          <label className="field-lbl">Firma *</label>
          <SignaturePad onChange={setTrazo}/>
        </div>

        {/* 4 · UBICACIÓN best-effort */}
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 12 }}>
          <button type="button" className="btn secondary xs" onClick={pedirGeo} disabled={geoEstado === "pidiendo"}>
            <Icons.Map/> {geoEstado === "ok" ? "Ubicación adjuntada" : geoEstado === "pidiendo" ? "Obteniendo…" : "Adjuntar ubicación"}
          </button>
          <span style={{ fontSize: 11, color: "var(--fg-3)" }}>
            {geoEstado === "ok" ? `±${Math.round(geo.accuracy)} m` : geoEstado === "denegada" ? "Permiso denegado (opcional)" : geoEstado === "nd" ? "No disponible" : "Opcional"}
          </span>
        </div>

        {/* 5 · WRITE-BACK */}
        <label style={{ display: "flex", alignItems: "flex-start", gap: 8, fontSize: 12, color: "var(--fg-2)", marginBottom: 12, cursor: "pointer" }}>
          <input type="checkbox" checked={writeBack} onChange={(e) => setWriteBack(e.target.checked)} style={{ marginTop: 2 }}/>
          Guardar el teléfono y DNI declarados en la ficha del cliente (no pisa un DNI distinto ya guardado).
        </label>

        {!isLive && <div style={{ fontSize: 12, color: "var(--warning)", marginBottom: 8 }}>Conéctate a Supabase para firmar (ahora estás en datos de prueba).</div>}
        {aviso && <div style={{ fontSize: 12, color: "var(--warning)", marginBottom: 8 }}>{aviso}</div>}
        {error && <div style={{ fontSize: 12, color: "var(--revin-red)", marginBottom: 8 }}>{error}</div>}

        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <button type="button" className="btn secondary" onClick={onClose}>{aviso ? "Cerrar" : "Cancelar"}</button>
          <button type="submit" className="btn primary" disabled={busy || !isLive || !hayFirmante || !hayTrazo}>
            {busy ? "Registrando…" : "Firmar y registrar"}
          </button>
        </div>
      </form>
    </div>
  );
};

// =========================================================================
// ParteCard — parte firmado (BLOQUE FIRMADO inmutable + NOTAS editables)
// =========================================================================
const ParteCard = ({ visita, onSaved }) => {
  const { Icons } = window;
  const RS = window.RevinSupabase;
  const firma = visita.firma || {};
  const sello = visita.selloFirma ? new Date(visita.selloFirma).toLocaleString("es-ES") : "—";

  const [verSnap, setVerSnap] = React.useState(false);
  const [editando, setEditando] = React.useState(false);
  const [val, setVal] = React.useState(visita.valoracion == null ? "" : String(visita.valoracion));
  const [com, setCom] = React.useState(visita.comentario || "");
  const [obj, setObj] = React.useState((visita.objeciones || []).join(", "));
  const [sig, setSig] = React.useState(visita.siguientePaso || "");
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);

  const guardarNotas = async () => {
    setBusy(true); setErr(null);
    try {
      // SOLO notas: nunca toca firma ni snapshot (bloque firmado inmutable).
      await RS.actualizarNotasVisita(visita.id, {
        valoracion: val === "" ? null : Number(val),
        comentario: com.trim() || null,
        objeciones: obj.trim() ? obj.split(",").map(s => s.trim()).filter(Boolean) : null,
        siguiente_paso: sig.trim() || null,
      });
      const data = await RS.loadDataFromSupabase(); window.DATA = data;
      setEditando(false); onSaved && onSaved();
    } catch (e) { console.error(e); setErr(e.message || "No se pudo guardar."); }
    finally { setBusy(false); }
  };

  return (
    <div style={{ border: "1px solid var(--border-1)", borderRadius: 8, padding: 12, marginBottom: 10 }}>
      {/* BLOQUE FIRMADO · inmutable, solo lectura */}
      <div style={{ display: "flex", justifyContent: "space-between", gap: 12, alignItems: "flex-start" }}>
        <div>
          <div style={{ fontWeight: 600 }}>{visita.client}</div>
          <div style={{ fontSize: 11, color: "var(--fg-3)", fontFamily: "var(--font-mono)" }}>
            Firmado: {sello}{firma.firmante && firma.firmante.dni_declarado ? ` · DNI ${firma.firmante.dni_declarado}` : ""}
          </div>
          {firma.geo && <div style={{ fontSize: 10, color: "var(--fg-4)" }}>◎ {firma.geo.lat.toFixed(5)}, {firma.geo.lng.toFixed(5)} (±{Math.round(firma.geo.accuracy)} m)</div>}
        </div>
        <FirmaSVG trazo={firma.trazo} maxWidth={170}/>
      </div>
      <button type="button" className="btn ghost xs" style={{ marginTop: 6 }} onClick={() => setVerSnap(s => !s)}>
        {verSnap ? "Ocultar" : "Ver"} texto firmado
      </button>
      {verSnap && (
        <pre style={{ whiteSpace: "pre-wrap", fontSize: 11, lineHeight: 1.5, background: "var(--bg-1, #f6f6f6)", padding: 10, borderRadius: 6, marginTop: 6 }}>{firma.snapshot}</pre>
      )}

      {/* BLOQUE NOTAS · editable siempre */}
      <div style={{ borderTop: "1px dashed var(--border-1)", marginTop: 10, paddingTop: 10 }}>
        {!editando ? (
          <>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 4 }}>
              <span style={{ fontSize: 10, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: ".08em" }}>Notas del comercial</span>
              <button type="button" className="btn ghost xs" onClick={() => setEditando(true)}>Editar notas</button>
            </div>
            {visita.valoracion ? <div style={{ fontSize: 12 }}>Valoración: <b>{visita.valoracion}/5</b></div> : null}
            {visita.comentario ? <div style={{ fontSize: 12, fontStyle: "italic", color: "var(--fg-2)" }}>"{visita.comentario}"</div>
              : (!visita.valoracion ? <div style={{ fontSize: 12, color: "var(--fg-4)" }}>Sin notas todavía.</div> : null)}
            {(visita.objeciones || []).length > 0 && (
              <div style={{ marginTop: 4 }}>{visita.objeciones.map((o, j) => <span key={j} className="visit-obj-chip">{o}</span>)}</div>
            )}
            {visita.siguientePaso ? <div style={{ fontSize: 12, color: "var(--fg-2)", marginTop: 2 }}>Siguiente: {visita.siguientePaso}</div> : null}
          </>
        ) : (
          <div style={{ display: "grid", gap: 8 }}>
            <div className="field" style={{ margin: 0 }}>
              <label className="field-lbl">Valoración (1-5)</label>
              <select className="input" value={val} onChange={e => setVal(e.target.value)}>
                <option value="">—</option>{[1, 2, 3, 4, 5].map(n => <option key={n} value={n}>{n}</option>)}
              </select>
            </div>
            <div className="field" style={{ margin: 0 }}>
              <label className="field-lbl">Comentario</label>
              <textarea className="input" rows={2} value={com} onChange={e => setCom(e.target.value)}/>
            </div>
            <div className="field" style={{ margin: 0 }}>
              <label className="field-lbl">Objeciones (separadas por coma)</label>
              <input className="input" value={obj} onChange={e => setObj(e.target.value)} placeholder="precio, orientación…"/>
            </div>
            <div className="field" style={{ margin: 0 }}>
              <label className="field-lbl">Siguiente paso</label>
              <input className="input" value={sig} onChange={e => setSig(e.target.value)}/>
            </div>
            {err && <div style={{ fontSize: 12, color: "var(--revin-red)" }}>{err}</div>}
            <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
              <button type="button" className="btn secondary xs" onClick={() => setEditando(false)}>Cancelar</button>
              <button type="button" className="btn primary xs" onClick={guardarNotas} disabled={busy}>{busy ? "Guardando…" : "Guardar notas"}</button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

window.FirmaVisita = { Modal: FirmarParteVisitaModal, SVG: FirmaSVG, SignaturePad, ParteCard, construirSnapshotVisita, TEXTO_LOPD };
