(() => {
  const $ = (id) => document.getElementById(id);
  const esc = (v) => String(v ?? "").replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#039;");
  const num = (v) => {
    if (v === null || v === undefined || v === "") return null;
    const n = Number(v);
    return Number.isFinite(n) ? n : null;
  };

  const API = "../php/geolocalizacion_comunitaria";
  // Vista inicial aproximada de Panquehue.
  const PANQUEHUE_BOUNDS = [[-32.804165, -70.948224], [-32.755789, -70.739231]];
  const PANQUEHUE_CENTER = [-32.7800, -70.8450];

  // Área de trabajo más amplia para poder hacer zoom y recorrer calles/caminos
  // sin que Leaflet bloquee el desplazamiento al borde de los límites iniciales.
  // Esto evita el efecto de "mapa pegado" cuando se trabaja calle por calle.
  const PANQUEHUE_WORK_BOUNDS = [[-32.8750, -71.0350], [-32.7000, -70.6100]];

  const els = {
    kpiActivos: $("kpiActivos"), kpiAgentes: $("kpiAgentes"), kpiVinculados: $("kpiVinculados"), kpiSectores: $("kpiSectores"),
    btnRecentrarMapa: $("btnRecentrarMapa"), btnRecargarPuntos: $("btnRecargarPuntos"), btnImprimirMapa: $("btnImprimirMapa"), btnNuevoPunto: $("btnNuevoPunto"),
    badgeTotalPuntos: $("badgeTotalPuntos"), badgeReadOnly: $("badgeReadOnly"), mapStatus: $("mapStatus"),
    fTexto: $("fTexto"), fTipo: $("fTipo"), fEstado: $("fEstado"), fCategoria: $("fCategoria"), fSectorizacion: $("fSectorizacion"), fSector: $("fSector"),
    btnAplicarFiltros: $("btnAplicarFiltros"), btnLimpiarFiltros: $("btnLimpiarFiltros"),
    legendList: $("legendList"), categorySummary: $("categorySummary"),
    formPunto: $("formPunto"), readonlyNote: $("readonlyNote"), editorPanel: $("editorPanel"),
    pId: $("pId"), pTipo: $("pTipo"), pEstado: $("pEstado"), pCategoria: $("pCategoria"), pNombre: $("pNombre"),
    agentBox: $("agentBox"), pBuscarPersona: $("pBuscarPersona"), btnBuscarPersona: $("btnBuscarPersona"), personResults: $("personResults"), pRutPersona: $("pRutPersona"), selectedPersonBox: $("selectedPersonBox"), pSyncPersona: $("pSyncPersona"),
    pContacto: $("pContacto"), pTelefono: $("pTelefono"), pCorreo: $("pCorreo"), pDireccion: $("pDireccion"), pSectorizacion: $("pSectorizacion"), pSector: $("pSector"), pLatitud: $("pLatitud"), pLongitud: $("pLongitud"),
    btnUsarCentroMapa: $("btnUsarCentroMapa"), btnUsarMiUbicacion: $("btnUsarMiUbicacion"), pDescripcion: $("pDescripcion"), pObservaciones: $("pObservaciones"), btnGuardarPunto: $("btnGuardarPunto"), btnEliminarPunto: $("btnEliminarPunto"), btnLimpiarFormulario: $("btnLimpiarFormulario"),
  };

  const state = {
    readonly: document.body.classList.contains("fp-monitor-readonly"),
    categorias: [],
    sectores: [],
    sectorizaciones: [],
    puntos: [],
    markers: null,
    selectedId: null,
    previewMarker: null,
  };

  const map = L.map("communityMap", {
    preferCanvas: true,
    // Límite blando y más amplio: permite recorrer todo el territorio con zoom
    // sin que el mapa se corte o quede amarrado a una zona pequeña.
    maxBounds: PANQUEHUE_WORK_BOUNDS,
    maxBoundsViscosity: 0.18,
    minZoom: 11,
    maxZoom: 20,
    zoomSnap: 0.25,
    zoomDelta: 0.5,
    wheelPxPerZoomLevel: 90,
  });

  const baseCalles = L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
    maxZoom: 20,
    maxNativeZoom: 19,
    keepBuffer: 4,
    updateWhenIdle: true,
    attribution: "&copy; OpenStreetMap"
  });

  // En zonas rurales Esri no siempre tiene teselas satelitales en zoom 18/19.
  // maxNativeZoom evita que Leaflet pida esos cuadros grises "Map data not yet available"
  // y reutiliza la mejor imagen disponible, permitiendo acercar sin perder el mapa.
  const baseSatelite = L.tileLayer("https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", {
    maxZoom: 20,
    maxNativeZoom: 17,
    keepBuffer: 4,
    updateWhenIdle: true,
    attribution: "Tiles &copy; Esri"
  });

  baseCalles.addTo(map);
  L.control.layers({
    "Calles": baseCalles,
    "Satélite / casas": baseSatelite,
  }, null, { position: "topright", collapsed: false }).addTo(map);

  map.fitBounds(PANQUEHUE_BOUNDS, { padding: [20, 20] });
  state.markers = L.markerClusterGroup({ chunkedLoading: true, maxClusterRadius: 42 });
  map.addLayer(state.markers);

  function api(path, options = {}) {
    return fetch(`${API}/${path}`, {
      credentials: "same-origin",
      cache: "no-store",
      headers: { "Content-Type": "application/json", "Accept": "application/json" },
      ...options,
    }).then(async (res) => {
      let data = null;
      try { data = await res.json(); } catch (e) {}
      if (!res.ok || !data?.ok) throw new Error(data?.message || `Error HTTP ${res.status}`);
      return data;
    });
  }

  function opt(value, text, selected = false) {
    return `<option value="${esc(value)}" ${selected ? "selected" : ""}>${esc(text)}</option>`;
  }

  function categoryFor(id) {
    return state.categorias.find(c => String(c.id) === String(id)) || null;
  }

  function categoriesByType(tipo) {
    return state.categorias.filter(c => !tipo || c.tipo === tipo);
  }

  function sectorsBySectorizacion(sz) {
    return state.sectores.filter(s => !sz || String(s.sectorizacion || "") === String(sz));
  }

  function fillCategorySelect(select, tipo, includeAll = false) {
    const current = select.value;
    let html = includeAll ? opt("", "Todas") : opt("", "Selecciona...");
    html += categoriesByType(tipo).map(c => opt(c.id, `${c.nombre}`)).join("");
    select.innerHTML = html;
    if ([...select.options].some(o => o.value === current)) select.value = current;
  }

  function fillSectorizacionSelect(select, includeAll = false) {
    const current = select.value;
    let html = includeAll ? opt("", "Todas") : opt("", "Sin asignar");
    html += state.sectorizaciones.map(s => opt(s.id, s.nombre_sectorizacion)).join("");
    select.innerHTML = html;
    if ([...select.options].some(o => o.value === current)) select.value = current;
  }

  function fillSectorSelect(select, sectorizacion, includeAll = false) {
    const current = select.value;
    let html = includeAll ? opt("", "Todos") : opt("", "Sin asignar");
    html += sectorsBySectorizacion(sectorizacion).map(s => opt(s.id, s.nombre_sector)).join("");
    select.innerHTML = html;
    if ([...select.options].some(o => o.value === current)) select.value = current;
  }

  function markerIcon(p, preview = false) {
    const c = categoryFor(p.categoria_id) || { color: "#2563eb", icono: "bi-geo-alt-fill" };
    const color = c.color || "#2563eb";
    const icon = c.icono || "bi-geo-alt-fill";
    const tipo = p.tipo === "agente" ? "agente" : "activo";
    return L.divIcon({
      className: "community-div-icon",
      html: `<div class="community-marker ${tipo} ${preview ? "preview" : ""}" style="background:${esc(color)};--pin-color:${esc(color)}"><i class="bi ${esc(icon)}"></i></div>`,
      iconSize: [34, 44], iconAnchor: [17, 42], popupAnchor: [0, -39]
    });
  }

  function puntoTitle(p) {
    const cat = p.categoria_nombre || categoryFor(p.categoria_id)?.nombre || "Sin categoría";
    return `${p.tipo === "agente" ? "Agente" : "Activo"} · ${cat}`;
  }

  function popupHtml(p) {
    const cat = categoryFor(p.categoria_id) || { color: p.categoria_color || "#2563eb", icono: p.categoria_icono || "bi-geo-alt-fill", nombre: p.categoria_nombre || "Sin categoría" };
    const persona = [p.persona_nombres, p.persona_apellidos].filter(Boolean).join(" ").trim();
    const phone = p.telefono || p.persona_celular || p.persona_telefonos || "";
    const gmaps = `https://www.google.com/maps?q=${encodeURIComponent(p.latitud + "," + p.longitud)}`;
    return `
      <div class="community-popup">
        <span class="popup-badge" style="background:${esc(cat.color || "#2563eb")}"><i class="bi ${esc(cat.icono || "bi-geo-alt-fill")}"></i> ${esc(cat.nombre || "Sin categoría")}</span>
        <div class="popup-title mt-2">${esc(p.nombre)}</div>
        <div class="popup-grid">
          <div><b>Tipo:</b> ${esc(p.tipo === "agente" ? "Agente comunitario" : "Activo comunitario")}</div>
          ${p.rut_persona ? `<div><b>Persona vinculada:</b> ${esc(p.rut_persona)} ${persona ? "· " + esc(persona) : ""}</div>` : ""}
          ${p.contacto_nombre ? `<div><b>Contacto:</b> ${esc(p.contacto_nombre)}</div>` : ""}
          ${phone ? `<div><b>Teléfono:</b> ${esc(phone)}</div>` : ""}
          ${p.direccion ? `<div><b>Dirección:</b> ${esc(p.direccion)}</div>` : ""}
          ${p.nombre_sector ? `<div><b>Sector:</b> ${esc(p.nombre_sector)}</div>` : ""}
          ${p.descripcion ? `<div><b>Aporte:</b> ${esc(p.descripcion)}</div>` : ""}
          <div><b>Coordenadas:</b> ${Number(p.latitud).toFixed(6)}, ${Number(p.longitud).toFixed(6)}</div>
        </div>
        <div class="popup-actions">
          <a class="btn-mini" href="${gmaps}" target="_blank" rel="noopener"><i class="bi bi-google"></i> Maps</a>
          <button class="btn-mini" type="button" data-edit-punto="${esc(p.id)}"><i class="bi bi-pencil"></i> Abrir</button>
          ${state.readonly ? "" : `<button class="btn-mini danger" type="button" data-del-punto="${esc(p.id)}"><i class="bi bi-trash"></i> Eliminar</button>`}
        </div>
      </div>`;
  }

  function renderMarkers() {
    state.markers.clearLayers();
    const bounds = [];
    for (const p of state.puntos) {
      const lat = num(p.latitud), lng = num(p.longitud);
      if (lat === null || lng === null) continue;
      const marker = L.marker([lat, lng], { icon: markerIcon(p) });
      marker.bindPopup(popupHtml(p), { maxWidth: 360 });
      marker.on("click", () => { state.selectedId = Number(p.id); });
      state.markers.addLayer(marker);
      bounds.push([lat, lng]);
    }
    if (bounds.length) {
      const b = L.latLngBounds(bounds);
      map.fitBounds(b.pad(.15), { maxZoom: 16 });
    } else {
      map.fitBounds(PANQUEHUE_BOUNDS, { padding: [20, 20] });
    }
    els.badgeTotalPuntos.textContent = `${state.puntos.length} puntos`;
  }

  function renderLegend() {
    const categories = categoriesByType(els.fTipo.value || "");
    els.legendList.innerHTML = categories.length ? categories.map(c => `
      <div class="legend-item">
        <span class="legend-dot" style="background:${esc(c.color)}"><i class="bi ${esc(c.icono)}"></i></span>
        <span>${esc(c.nombre)}</span>
      </div>`).join("") : `<div class="empty-small">No hay categorías para mostrar.</div>`;
  }

  function renderCategorySummary(categoryStats) {
    if (!categoryStats?.length) {
      els.categorySummary.innerHTML = `<div class="empty-small">Sin puntos comunitarios para los filtros aplicados.</div>`;
      return;
    }
    els.categorySummary.innerHTML = categoryStats.slice(0, 12).map(r => `
      <div class="cat-chip">
        <span class="cat-left"><span class="cat-color" style="background:${esc(r.color || "#64748b")}"></span><span class="cat-name">${esc(r.categoria)}</span></span>
        <b>${esc(r.total)}</b>
      </div>`).join("");
  }

  function updateKpis(stats = {}) {
    els.kpiActivos.textContent = Number(stats.activos || 0).toLocaleString("es-CL");
    els.kpiAgentes.textContent = Number(stats.agentes || 0).toLocaleString("es-CL");
    els.kpiVinculados.textContent = Number(stats.vinculados || 0).toLocaleString("es-CL");
    els.kpiSectores.textContent = Number(stats.sectores_con_puntos || 0).toLocaleString("es-CL");
  }

  function getFilters() {
    return {
      q: els.fTexto.value.trim(),
      tipo: els.fTipo.value,
      estado: els.fEstado.value,
      categoria_id: els.fCategoria.value,
      sectorizacion: els.fSectorizacion.value,
      sector: els.fSector.value,
      limit: 5000,
    };
  }

  async function loadPuntos() {
    els.mapStatus.textContent = "Cargando puntos comunitarios...";
    try {
      const data = await api("list.php", { method: "POST", body: JSON.stringify(getFilters()) });
      state.readonly = !!data.readonly || state.readonly;
      state.puntos = data.data || [];
      updateReadOnlyUi();
      updateKpis(data.stats || {});
      renderCategorySummary(data.category_stats || []);
      renderMarkers();
      els.mapStatus.textContent = state.puntos.length ? "Mapa comunitario actualizado." : "Sin puntos para los filtros aplicados.";
    } catch (e) {
      els.mapStatus.textContent = "No se pudieron cargar los puntos.";
      Swal.fire("Error", e.message, "error");
    }
  }

  async function loadFilters() {
    const data = await api("filters.php");
    state.readonly = !!data.readonly || state.readonly;
    state.categorias = data.categorias || [];
    state.sectorizaciones = data.sectorizaciones || [];
    state.sectores = data.sectores || [];
    fillCategorySelect(els.fCategoria, els.fTipo.value, true);
    fillCategorySelect(els.pCategoria, els.pTipo.value, false);
    fillSectorizacionSelect(els.fSectorizacion, true);
    fillSectorizacionSelect(els.pSectorizacion, false);
    fillSectorSelect(els.fSector, els.fSectorizacion.value, true);
    fillSectorSelect(els.pSector, els.pSectorizacion.value, false);
    renderLegend();
    updateReadOnlyUi();
  }

  function setPreviewLatLng(lat, lng, moveMap = false) {
    const ll = [Number(lat), Number(lng)];
    els.pLatitud.value = ll[0].toFixed(6);
    els.pLongitud.value = ll[1].toFixed(6);
    const p = { tipo: els.pTipo.value, categoria_id: els.pCategoria.value || null };
    if (!state.previewMarker) {
      state.previewMarker = L.marker(ll, { draggable: !state.readonly, icon: markerIcon(p, true) }).addTo(map);
      state.previewMarker.on("dragend", () => {
        const pos = state.previewMarker.getLatLng();
        setPreviewLatLng(pos.lat, pos.lng, false);
      });
    } else {
      state.previewMarker.setLatLng(ll);
      state.previewMarker.setIcon(markerIcon(p, true));
    }
    if (moveMap) map.setView(ll, Math.max(map.getZoom(), 16), { animate: true });
    els.mapStatus.textContent = `Ubicación preparada: ${ll[0].toFixed(6)}, ${ll[1].toFixed(6)}`;
  }

  function clearPreview() {
    if (state.previewMarker) {
      map.removeLayer(state.previewMarker);
      state.previewMarker = null;
    }
  }

  function resetForm() {
    els.formPunto.reset();
    els.pId.value = "";
    els.pTipo.value = "activo";
    els.pEstado.value = "activo";
    els.pRutPersona.value = "";
    els.selectedPersonBox.classList.add("d-none");
    els.selectedPersonBox.innerHTML = "";
    els.personResults.innerHTML = "";
    fillCategorySelect(els.pCategoria, els.pTipo.value, false);
    fillSectorizacionSelect(els.pSectorizacion, false);
    fillSectorSelect(els.pSector, "", false);
    els.btnEliminarPunto.disabled = true;
    state.selectedId = null;
    clearPreview();
    updateAgentBox();
  }

  function updateAgentBox() {
    const isAgent = els.pTipo.value === "agente";
    els.agentBox.style.display = isAgent ? "block" : "none";
    fillCategorySelect(els.pCategoria, els.pTipo.value, false);
    if (state.previewMarker && els.pLatitud.value && els.pLongitud.value) {
      state.previewMarker.setIcon(markerIcon({ tipo: els.pTipo.value, categoria_id: els.pCategoria.value }, true));
    }
  }

  function selectPunto(p) {
    state.selectedId = Number(p.id);
    els.pId.value = p.id || "";
    els.pTipo.value = p.tipo || "activo";
    updateAgentBox();
    els.pEstado.value = p.estado || "activo";
    fillCategorySelect(els.pCategoria, els.pTipo.value, false);
    els.pCategoria.value = p.categoria_id || "";
    els.pNombre.value = p.nombre || "";
    els.pRutPersona.value = p.rut_persona || "";
    els.pContacto.value = p.contacto_nombre || "";
    els.pTelefono.value = p.telefono || p.persona_celular || p.persona_telefonos || "";
    els.pCorreo.value = p.correo || "";
    els.pDireccion.value = p.direccion || p.persona_direccion || "";
    els.pSectorizacion.value = p.sectorizacion || "";
    fillSectorSelect(els.pSector, els.pSectorizacion.value, false);
    els.pSector.value = p.sector || "";
    els.pDescripcion.value = p.descripcion || "";
    els.pObservaciones.value = p.observaciones || "";
    setPreviewLatLng(p.latitud, p.longitud, true);
    els.btnEliminarPunto.disabled = state.readonly || !p.id;
    renderSelectedPersonFromPunto(p);
    els.editorPanel.scrollIntoView({ behavior: "smooth", block: "start" });
  }

  function renderSelectedPersonFromPunto(p) {
    if (!p.rut_persona) {
      els.selectedPersonBox.classList.add("d-none");
      els.selectedPersonBox.innerHTML = "";
      return;
    }
    const name = [p.persona_nombres, p.persona_apellidos].filter(Boolean).join(" ").trim() || p.contacto_nombre || "Persona vinculada";
    els.selectedPersonBox.classList.remove("d-none");
    els.selectedPersonBox.innerHTML = `<div class="fw-bold"><i class="bi bi-check-circle-fill text-success"></i> ${esc(name)}</div><div class="small text-muted">RUT ${esc(p.rut_persona)} · ${esc(p.persona_direccion || p.direccion || "Sin dirección")}</div>`;
  }

  function payloadFromForm() {
    return {
      id: els.pId.value || null,
      tipo: els.pTipo.value,
      estado: els.pEstado.value,
      categoria_id: els.pCategoria.value,
      nombre: els.pNombre.value.trim(),
      rut_persona: els.pRutPersona.value.trim(),
      contacto_nombre: els.pContacto.value.trim(),
      telefono: els.pTelefono.value.trim(),
      correo: els.pCorreo.value.trim(),
      direccion: els.pDireccion.value.trim(),
      sectorizacion: els.pSectorizacion.value,
      sector: els.pSector.value,
      latitud: els.pLatitud.value,
      longitud: els.pLongitud.value,
      descripcion: els.pDescripcion.value.trim(),
      observaciones: els.pObservaciones.value.trim(),
      sync_persona: els.pSyncPersona.checked,
    };
  }

  async function savePunto(ev) {
    ev.preventDefault();
    if (state.readonly) return Swal.fire("Solo lectura", "El rol monitor no puede guardar puntos comunitarios.", "info");
    const payload = payloadFromForm();
    const estabaEditando = !!payload.id;
    if (!payload.nombre) return Swal.fire("Falta nombre", "Debes escribir el nombre del activo o agente comunitario.", "warning");
    if (!payload.categoria_id) return Swal.fire("Falta categoría", "Debes seleccionar una categoría.", "warning");
    if (!payload.latitud || !payload.longitud) return Swal.fire("Falta ubicación", "Haz clic en el mapa o usa el centro del mapa para asignar coordenadas.", "warning");

    try {
      els.btnGuardarPunto.disabled = true;
      els.btnGuardarPunto.innerHTML = `<span class="spinner-border spinner-border-sm me-1"></span> Guardando...`;
      const data = await api("save.php", { method: "POST", body: JSON.stringify(payload) });
      await loadPuntos();
      resetForm();
      els.mapStatus.textContent = estabaEditando
        ? "Punto comunitario actualizado. Formulario limpio para crear uno nuevo."
        : "Punto comunitario guardado. Formulario limpio para crear uno nuevo.";
      await Swal.fire({ icon: "success", title: "Guardado", text: data.message || "Punto comunitario guardado.", timer: 1200, showConfirmButton: false });
    } catch (e) {
      Swal.fire("Error", e.message, "error");
    } finally {
      els.btnGuardarPunto.disabled = state.readonly;
      els.btnGuardarPunto.innerHTML = `<i class="bi bi-save"></i> Guardar punto comunitario`;
    }
  }

  async function deletePunto(id = null) {
    if (state.readonly) return Swal.fire("Solo lectura", "El rol monitor no puede eliminar puntos comunitarios.", "info");
    id = id || els.pId.value;
    if (!id) return;
    const res = await Swal.fire({
      icon: "warning", title: "¿Eliminar punto comunitario?", text: "Esta acción quitará el punto del mapa.",
      showCancelButton: true, confirmButtonText: "Sí, eliminar", cancelButtonText: "Cancelar", reverseButtons: true
    });
    if (!res.isConfirmed) return;
    try {
      await api("delete.php", { method: "POST", body: JSON.stringify({ id }) });
      resetForm();
      await loadPuntos();
      Swal.fire({ icon: "success", title: "Eliminado", timer: 1000, showConfirmButton: false });
    } catch (e) {
      Swal.fire("Error", e.message, "error");
    }
  }

  async function searchPerson() {
    const q = els.pBuscarPersona.value.trim();
    if (!q) return;
    els.personResults.innerHTML = `<div class="empty-small">Buscando persona...</div>`;
    try {
      const data = await api("search_person.php", { method: "POST", body: JSON.stringify({ q }) });
      const rows = data.data || [];
      if (!rows.length) {
        els.personResults.innerHTML = `<div class="empty-small">No se encontraron personas registradas.</div>`;
        return;
      }
      els.personResults.innerHTML = rows.map(p => {
        const name = [p.nombres, p.apellidos].filter(Boolean).join(" ").trim() || p.nombre_completo || "Sin nombre";
        return `<button class="person-card text-start w-100" type="button" data-person='${esc(JSON.stringify(p))}'>
          <div class="person-name">${esc(name)}</div>
          <div class="person-meta">RUT ${esc(p.rut)} · ${esc(p.direccion || "Sin dirección")} ${p.latitud && p.longitud ? "· con coordenadas" : ""}</div>
        </button>`;
      }).join("");
    } catch (e) {
      els.personResults.innerHTML = `<div class="empty-small">Error buscando persona.</div>`;
      Swal.fire("Error", e.message, "error");
    }
  }

  function selectPerson(p) {
    const name = [p.nombres, p.apellidos].filter(Boolean).join(" ").trim() || p.nombre_completo || "Persona vinculada";
    els.pRutPersona.value = p.rut || "";
    els.pContacto.value = name;
    els.pTelefono.value = p.celular || p.telefonos || els.pTelefono.value;
    els.pDireccion.value = p.direccion || els.pDireccion.value;
    els.pSectorizacion.value = p.sectorizacion || "";
    fillSectorSelect(els.pSector, els.pSectorizacion.value, false);
    els.pSector.value = p.sector || "";
    if (!els.pNombre.value.trim()) els.pNombre.value = name;
    if (p.latitud && p.longitud) setPreviewLatLng(p.latitud, p.longitud, true);
    els.selectedPersonBox.classList.remove("d-none");
    els.selectedPersonBox.innerHTML = `<div class="fw-bold"><i class="bi bi-check-circle-fill text-success"></i> ${esc(name)}</div><div class="small text-muted">RUT ${esc(p.rut)} · ${esc(p.direccion || "Sin dirección")}</div>`;
    els.personResults.innerHTML = "";
  }

  function updateReadOnlyUi() {
    if (!state.readonly) return;
    document.body.classList.add("fp-monitor-readonly");
    els.badgeReadOnly.classList.remove("d-none");
    els.readonlyNote.classList.remove("d-none");
    [els.btnGuardarPunto, els.btnEliminarPunto, els.btnNuevoPunto, els.btnUsarCentroMapa, els.btnUsarMiUbicacion, els.btnLimpiarFormulario].forEach(el => {
      if (el) el.disabled = true;
    });
    [...els.formPunto.querySelectorAll("input, select, textarea, button")].forEach(el => {
      if (["pBuscarPersona"].includes(el.id)) return;
      if (el.closest(".person-results")) return;
      el.disabled = true;
    });
    els.mapStatus.textContent = "Modo solo lectura: puedes revisar, filtrar e imprimir.";
  }

  map.on("click", (e) => {
    if (state.readonly) return;
    setPreviewLatLng(e.latlng.lat, e.latlng.lng, false);
    if (!els.pId.value && !els.pNombre.value.trim()) els.pNombre.focus();
  });

  document.addEventListener("click", (ev) => {
    const edit = ev.target.closest("[data-edit-punto]");
    if (edit) {
      const p = state.puntos.find(x => String(x.id) === String(edit.dataset.editPunto));
      if (p) selectPunto(p);
    }
    const del = ev.target.closest("[data-del-punto]");
    if (del) deletePunto(del.dataset.delPunto);
    const person = ev.target.closest("[data-person]");
    if (person) {
      try { selectPerson(JSON.parse(person.dataset.person || "{}")); } catch (e) {}
    }
  });

  els.formPunto.addEventListener("submit", savePunto);
  els.btnEliminarPunto.addEventListener("click", () => deletePunto());
  els.btnLimpiarFormulario.addEventListener("click", resetForm);
  els.btnNuevoPunto.addEventListener("click", () => { resetForm(); els.editorPanel.scrollIntoView({ behavior: "smooth", block: "start" }); });
  els.btnRecargarPuntos.addEventListener("click", loadPuntos);
  els.btnRecentrarMapa.addEventListener("click", () => map.fitBounds(PANQUEHUE_BOUNDS, { padding: [20, 20], animate: true }));
  els.btnImprimirMapa.addEventListener("click", () => window.print());
  els.btnAplicarFiltros.addEventListener("click", loadPuntos);
  els.btnLimpiarFiltros.addEventListener("click", () => {
    els.fTexto.value = ""; els.fTipo.value = ""; els.fEstado.value = "activo"; els.fSectorizacion.value = "";
    fillCategorySelect(els.fCategoria, "", true); fillSectorSelect(els.fSector, "", true); renderLegend(); loadPuntos();
  });
  els.fTipo.addEventListener("change", () => { fillCategorySelect(els.fCategoria, els.fTipo.value, true); renderLegend(); });
  els.fSectorizacion.addEventListener("change", () => fillSectorSelect(els.fSector, els.fSectorizacion.value, true));
  els.fTexto.addEventListener("keydown", (e) => { if (e.key === "Enter") loadPuntos(); });
  els.pTipo.addEventListener("change", updateAgentBox);
  els.pCategoria.addEventListener("change", () => {
    if (state.previewMarker && els.pLatitud.value && els.pLongitud.value) state.previewMarker.setIcon(markerIcon({ tipo: els.pTipo.value, categoria_id: els.pCategoria.value }, true));
  });
  els.pSectorizacion.addEventListener("change", () => fillSectorSelect(els.pSector, els.pSectorizacion.value, false));
  els.btnUsarCentroMapa.addEventListener("click", () => {
    const c = map.getCenter(); setPreviewLatLng(c.lat, c.lng, false);
  });
  els.btnUsarMiUbicacion.addEventListener("click", () => {
    if (!navigator.geolocation) return Swal.fire("GPS no disponible", "Tu navegador no permite usar geolocalización.", "info");
    navigator.geolocation.getCurrentPosition((pos) => {
      setPreviewLatLng(pos.coords.latitude, pos.coords.longitude, true);
    }, () => Swal.fire("No se pudo obtener GPS", "Revisa permisos de ubicación del navegador.", "warning"), { enableHighAccuracy: true, timeout: 10000 });
  });
  els.btnBuscarPersona.addEventListener("click", searchPerson);
  els.pBuscarPersona.addEventListener("keydown", (e) => { if (e.key === "Enter") { e.preventDefault(); searchPerson(); } });

  (async () => {
    try {
      await loadFilters();
      updateAgentBox();
      await loadPuntos();
      setTimeout(() => map.invalidateSize(), 250);
      document.addEventListener("fp:sidebar-toggle", () => setTimeout(() => map.invalidateSize(), 260));
    } catch (e) {
      Swal.fire("Error", e.message || "No se pudo inicializar el módulo.", "error");
    }
  })();
})();
