(() => {
  const $ = (id) => document.getElementById(id);

  // ✅ Endpoint real
  const API_BUSQUEDA = "../php/busqueda/search.php";

  // ✅ Catálogos (Sectorización / Sectores)
  const API_SECTORIZACION = "../php/config/sectorizacion/list.php";
  const API_SECTORES = "../php/config/sectores/list.php";

  // Desktop filters
  const q = $("q");
  const btnClearQ = $("btnClearQ");
  const tPersonas = $("tPersonas");
  const tFamilias = $("tFamilias");
  const tViviendas = $("tViviendas");
  const fSz = $("fSz");
  const fSec = $("fSec");
  const fInscrito = $("fInscrito");
  const fPercapitado = $("fPercapitado");
  const fMigrante = $("fMigrante");
  const fGenero = $("fGenero");
  const fGeo = $("fGeo");
  const btnAplicar = $("btnAplicar");
  const btnReset = $("btnReset");

  // Mobile filters
  const qM = $("qM");
  const btnClearQM = $("btnClearQM");
  const tPersonasM = $("tPersonasM");
  const tFamiliasM = $("tFamiliasM");
  const tViviendasM = $("tViviendasM");
  const fSzM = $("fSzM");
  const fSecM = $("fSecM");
  const fInscritoM = $("fInscritoM");
  const fPercapitadoM = $("fPercapitadoM");
  const fMigranteM = $("fMigranteM");
  const fGeneroM = $("fGeneroM");
  const fGeoM = $("fGeoM");
  const btnAplicarM = $("btnAplicarM");
  const btnResetM = $("btnResetM");

  // UI
  const lblTotalBase = $("lblTotalBase");
  const btnRecargar = $("btnRecargar");

  const kpiTotal = $("kpiTotal");
  const kpiP = $("kpiP");
  const kpiF = $("kpiF");
  const kpiV = $("kpiV");

  const lblCount = $("lblCount");
  const lblP = $("lblP");
  const lblF = $("lblF");
  const lblV = $("lblV");

  const listP = $("listP");
  const listF = $("listF");
  const listV = $("listV");

  // Result sets (desde backend)
  let resP = [];
  let resF = [];
  let resV = [];

  // Meta
  let baseAll = null;

  // Lookups de Sectorización / Sectores (id -> nombre)
  let SZ_ROWS = [];
  let SEC_ROWS = [];
  let ALL_SEC = [];
  const MAP_SZ = new Map();      // "2" -> "B"
  const MAP_SEC = new Map();     // "10" -> {id:"10", sectorizacion:"2", nombre:"SAN ROQUE"}
  const SEC_BY_SZ = new Map();   // "2" -> [ {..}, .. ]

  // Helpers
  const safe = (v) => String(v ?? "");
  const esc = (s) => safe(s)
    .replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;")
    .replaceAll('"',"&quot;").replaceAll("'","&#039;");

  function idStr(v){
    const s = String(v ?? "").trim();
    return s === "" ? "" : s;
  }

  function toNum(v){
    const n = Number(String(v).replace(",", "."));
    return Number.isFinite(n) ? n : null;
  }

  function hasCoords(p){
    const lat = toNum(p.latitud);
    const lng = toNum(p.longitud);
    return lat !== null && lng !== null;
  }

  function markText(text, q){
    const t = safe(text);
    const needle = safe(q).trim();
    if (!needle) return esc(t);

    const low = t.toLowerCase();
    const nlow = needle.toLowerCase();
    const idx = low.indexOf(nlow);
    if (idx < 0) return esc(t);

    const a = t.slice(0, idx);
    const b = t.slice(idx, idx + needle.length);
    const c = t.slice(idx + needle.length);
    return `${esc(a)}<mark class="fp">${esc(b)}</mark>${esc(c)}`;
  }

  function debounce(fn, ms=250){
    let t; return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); };
  }

  async function fetchJSON(url, options = {}) {
    const res = await fetch(url, {
      credentials: "same-origin",
      cache: "no-store",
      headers: { "Content-Type": "application/json" },
      ...options
    });
    const data = await res.json().catch(() => null);
    if (!res.ok || !data || data.ok === false) {
      throw new Error(data?.message || "Error de servidor");
    }
    return data;
  }

  function sortEs(a, b){
    return String(a).localeCompare(String(b), "es", { numeric: true, sensitivity: "base" });
  }

  function buildLookups(szRows, secRows){
    SZ_ROWS = Array.isArray(szRows) ? szRows : [];
    SEC_ROWS = Array.isArray(secRows) ? secRows : [];

    MAP_SZ.clear();
    MAP_SEC.clear();
    SEC_BY_SZ.clear();

    // Sectorización
    for (const z of SZ_ROWS){
      const id = idStr(z.id);
      if (!id) continue;
      const name = String(z.nombre_sectorizacion ?? z.nombre ?? z.codigo ?? z.letra ?? "").trim() || id;
      MAP_SZ.set(id, name);
    }

    // Sectores
    for (const s of SEC_ROWS){
      const id = idStr(s.id);
      if (!id) continue;

      const sz = idStr(s.sectorizacion);
      const nombre = String(s.nombre_sector ?? s.nombre ?? "").trim() || id;

      const rec = { id, sectorizacion: sz, nombre };
      MAP_SEC.set(id, rec);

      if (!SEC_BY_SZ.has(sz)) SEC_BY_SZ.set(sz, []);
      SEC_BY_SZ.get(sz).push(rec);
    }

    // Orden
    SZ_ROWS = [...SZ_ROWS].sort((a,b) => sortEs(a.nombre_sectorizacion ?? a.nombre ?? a.id, b.nombre_sectorizacion ?? b.nombre ?? b.id));
    for (const [k, arr] of SEC_BY_SZ.entries()){
      arr.sort((a,b) => sortEs(a.nombre, b.nombre));
      SEC_BY_SZ.set(k, arr);
    }
    ALL_SEC = [...MAP_SEC.values()].sort((a,b) => sortEs(a.nombre, b.nombre));
  }

  function setOptionsKeepFirst(selectEl, rows, getValue, getLabel, keepValue = null){
    const keep = keepValue ?? selectEl.value;

    // Mantiene el primer option (value="") y limpia el resto
    const opts = Array.from(selectEl.querySelectorAll("option"));
    opts.slice(1).forEach(o => o.remove());

    for (const r of rows){
      const val = String(getValue(r) ?? "").trim();
      if (!val) continue;
      const label = String(getLabel(r) ?? "").trim() || val;
      const opt = document.createElement("option");
      opt.value = val;
      opt.textContent = label;
      selectEl.appendChild(opt);
    }

    // reintenta restaurar selección
    if (keep !== null && keep !== undefined && keep !== ""){
      const exists = Array.from(selectEl.options).some(o => o.value === String(keep));
      selectEl.value = exists ? String(keep) : "";
    } else {
      selectEl.value = "";
    }
  }

  function populateSectorizacionSelects(){
    if (!SZ_ROWS.length) return;
    setOptionsKeepFirst(fSz, SZ_ROWS, r => r.id, r => r.nombre_sectorizacion ?? r.nombre ?? r.id, fSz.value);
    setOptionsKeepFirst(fSzM, SZ_ROWS, r => r.id, r => r.nombre_sectorizacion ?? r.nombre ?? r.id, fSzM.value);
  }

  function sectorsFor(szId){
    const key = idStr(szId);
    if (!key) return ALL_SEC;
    return SEC_BY_SZ.get(key) ?? [];
  }

  function populateSectoresSelectsFrom(szId){
    const rows = sectorsFor(szId);
    setOptionsKeepFirst(fSec, rows, r => r.id, r => r.nombre, fSec.value);
    setOptionsKeepFirst(fSecM, rows, r => r.id, r => r.nombre, fSecM.value);
  }

  function resolveSector(row){
    const szId = idStr(row?.sectorizacion);
    const scId = idStr(row?.sector);

    const szName =
      String(row?.sectorizacion_nombre ?? row?.nombre_sectorizacion ?? "").trim() ||
      (szId ? (MAP_SZ.get(szId) || szId) : "—");

    let scName = String(row?.sector_nombre ?? row?.nombre_sector ?? "").trim();
    if (!scName && scId) {
      const rec = MAP_SEC.get(scId);
      if (rec) scName = rec.nombre;
    }
    if (!scName) scName = scId || "—";

    return { szId, scId, szName, scName };
  }

  async function loadCatalogs(){
    try {
      const z = await fetchJSON(API_SECTORIZACION, { method: "GET" });
      const s = await fetchJSON(API_SECTORES, { method: "GET" });

      const szRows = Array.isArray(z?.data) ? z.data : [];
      const secRows = Array.isArray(s?.data) ? s.data : [];

      buildLookups(szRows, secRows);

      // Reemplaza opciones hardcode por las reales (sin tocar HTML)
      populateSectorizacionSelects();
      populateSectoresSelectsFrom(fSz.value || "");

    } catch (e) {
      // Si falla por permisos o endpoint, NO rompemos la pantalla (queda el hardcode)
      console.warn("[busqueda] No se pudieron cargar catálogos:", e);
    }
  }

  // Acordeón exclusivo
  function wireAccordions(){
    const accordions = Array.from(document.querySelectorAll("details.acc"));
    if (!accordions.length) return;
    const opened = accordions.filter(a => a.hasAttribute("open"));
    if (opened.length > 1) opened.slice(1).forEach(a => a.removeAttribute("open"));
    accordions.forEach(acc => {
      acc.addEventListener("toggle", () => {
        if (!acc.open) return;
        accordions.forEach(o => { if (o !== acc && o.open) o.removeAttribute("open"); });
      });
    });
  }

  function syncMobileFromDesktop(){
    qM.value = q.value;
    tPersonasM.checked = tPersonas.checked;
    tFamiliasM.checked = tFamilias.checked;
    tViviendasM.checked = tViviendas.checked;

    // Mantiene dependencia: Sectorización -> Sectores
    fSzM.value = fSz.value;
    populateSectoresSelectsFrom(fSz.value || "");
    fSecM.value = fSec.value;

    fInscritoM.value = fInscrito.value;
    fPercapitadoM.value = fPercapitado.value;
    fMigranteM.value = fMigrante.value;
    fGeneroM.value = fGenero.value;
    fGeoM.value = fGeo.value;
  }

  function syncDesktopFromMobile(){
    q.value = qM.value;
    tPersonas.checked = tPersonasM.checked;
    tFamilias.checked = tFamiliasM.checked;
    tViviendas.checked = tViviendasM.checked;

    // Mantiene dependencia: Sectorización -> Sectores
    fSz.value = fSzM.value;
    populateSectoresSelectsFrom(fSzM.value || "");
    fSec.value = fSecM.value;

    fInscrito.value = fInscritoM.value;
    fPercapitado.value = fPercapitadoM.value;
    fMigrante.value = fMigranteM.value;
    fGenero.value = fGeneroM.value;
    fGeo.value = fGeoM.value;
  }

  function filters(){
    return {
      q: (q.value || "").trim(),
      types: {
        p: !!tPersonas.checked,
        f: !!tFamilias.checked,
        v: !!tViviendas.checked
      },
      sz: fSz.value,
      sec: fSec.value,
      inscrito: fInscrito.value,
      percapitado: fPercapitado.value,
      migrante: fMigrante.value,
      genero: fGenero.value,
      geo: fGeo.value
    };
  }

  // ===== Render =====
  function renderKPIs(){
    const total = resP.length + resF.length + resV.length;
    kpiTotal.textContent = total;
    kpiP.textContent = resP.length;
    kpiF.textContent = resF.length;
    kpiV.textContent = resV.length;

    lblP.textContent = `${resP.length} coincidencias`;
    lblF.textContent = `${resF.length} coincidencias`;
    lblV.textContent = `${resV.length} coincidencias`;

    lblCount.textContent = `Personas: ${resP.length} · Familias: ${resF.length} · Viviendas: ${resV.length}`;
  }

  function renderList(listEl, items, renderer){
    listEl.innerHTML = "";

    if (!items.length){
      listEl.innerHTML = `<div class="p-3 text-muted">Sin resultados.</div>`;
      return;
    }

    const limit = 250;
    const slice = items.slice(0, limit);

    const frag = document.createDocumentFragment();
    slice.forEach((it) => {
      const div = document.createElement("div");
      div.className = "result-item";
      div.innerHTML = renderer(it);
      frag.appendChild(div);
    });
    listEl.appendChild(frag);

    if (items.length > limit){
      const more = document.createElement("div");
      more.className = "p-2 text-muted small";
      more.textContent = `Mostrando ${limit} de ${items.length}. Usa más filtros para acotar.`;
      listEl.appendChild(more);
    }
  }

  function renderAll(){
    renderKPIs();

    const query = (q.value || "").trim();

    renderList(listP, resP, (p) => {
      const full = `${safe(p.nombres)} ${safe(p.apellidos)}`.trim() || "Sin nombre";
      const rut = safe(p.rut || "—");
      const dir = safe(p.direccion || "—");
      const { szName, scName } = resolveSector(p);

      const inscr = (p.inscrito_cesfam == 1 || p.inscrito_cesfam === true) ? "Sí" : "No";
      const perc = (p.percapitado == 1 || p.percapitado === true) ? "Percapitado" : "No percapitado";
      const gen = safe(p.genero || "—");
      const geo = hasCoords(p) ? "Sí" : "No";

      return `
        <div>
          <div class="name">${markText(full, query)}</div>
          <div class="meta">${markText(rut, query)} · Inscrito: ${esc(inscr)} · Género: ${esc(gen)} · Coord: ${esc(geo)}</div>
          <div class="meta">${markText(dir, query)} · Sector: ${esc(szName)} / ${esc(scName)}</div>
        </div>
        <div class="badges">
          <button class="btn-mini" type="button" data-act="open" data-type="persona" data-id="${esc(rut)}" title="Abrir en Personas">
            <i class="bi bi-box-arrow-up-right"></i>
          </button>
          <button class="btn-mini" type="button" data-act="view" data-type="persona" data-id="${esc(rut)}" title="Ver detalle">
            <i class="bi bi-eye"></i>
          </button>
          <button class="btn-mini" type="button" data-act="geo" data-type="persona" data-id="${esc(rut)}" title="Ver en Geolocalización">
            <i class="bi bi-geo-alt"></i>
          </button>
        </div>
      `;
    });

    renderList(listF, resF, (f) => {
      const code = safe(f.cod_familia || f.codigo_familia || "—");
      const ap = safe(f.apellido_familia || "Sin apellido");
      const dir = safe(f.direccion || "—");
      const { szName, scName } = resolveSector(f);
      const nInt = Number(f.total_integrantes ?? 0);

      return `
        <div>
          <div class="name">${markText(`${code} · ${ap}`, query)}</div>
          <div class="meta">${markText(dir, query)} · Sector: ${esc(szName)} / ${esc(scName)} · Integrantes: ${esc(nInt)}</div>
        </div>
        <div class="badges">
          <button class="btn-mini" type="button" data-act="open" data-type="familia" data-id="${esc(code)}" title="Abrir en Familias">
            <i class="bi bi-box-arrow-up-right"></i>
          </button>
          <button class="btn-mini" type="button" data-act="view" data-type="familia" data-id="${esc(code)}" title="Ver detalle">
            <i class="bi bi-eye"></i>
          </button>
        </div>
      `;
    });

    renderList(listV, resV, (v) => {
      const code = safe(v.cod_vivienda || v.codigo_vivienda || v.cod || v.id || "—");
      const dir = safe(v.direccion || "—");
      const { szName, scName } = resolveSector(v);
      const tv = safe(v.tipo_vivienda || v.tipo || "—");
      const ten = safe(v.tenencia || "—");

      return `
        <div>
          <div class="name">${markText(`${code}`, query)}</div>
          <div class="meta">${markText(dir, query)} · Sector: ${esc(szName)} / ${esc(scName)}</div>
          <div class="meta">Tipo: ${esc(tv)} · Tenencia: ${esc(ten)}</div>
        </div>
        <div class="badges">
          <button class="btn-mini" type="button" data-act="open" data-type="vivienda" data-id="${esc(code)}" title="Abrir en Vivienda">
            <i class="bi bi-box-arrow-up-right"></i>
          </button>
          <button class="btn-mini" type="button" data-act="view" data-type="vivienda" data-id="${esc(code)}" title="Ver detalle">
            <i class="bi bi-eye"></i>
          </button>
        </div>
      `;
    });
  }

  // ===== Actions =====
  function rememberSelection(type, id){
    localStorage.setItem("fp_busqueda_sel_v1", JSON.stringify({
      type, id, at: new Date().toISOString()
    }));
  }

  async function viewDetail(type, id){
    if (type === "persona"){
      const p = resP.find(x => String(x.rut||"").trim() === String(id).trim());
      if (!p) return;

      const full = `${safe(p.nombres)} ${safe(p.apellidos)}`.trim();
      const geo = hasCoords(p) ? `${p.latitud}, ${p.longitud}` : "—";
      const { szName, scName } = resolveSector(p);

      await Swal.fire({
        icon: "info",
        title: full || "Persona",
        html: `
          <div style="text-align:left">
            <div><b>RUT:</b> ${esc(p.rut||"—")}</div>
            <div><b>Dirección:</b> ${esc(p.direccion||"—")}</div>
            <div><b>Inscrito CESFAM:</b> ${esc((p.inscrito_cesfam==1||p.inscrito_cesfam===true) ? "Sí":"No")}</div>
            <div><b>Percápita FONASA:</b> ${esc((p.percapitado==1||p.percapitado===true) ? "Sí":"No")}</div>
            <div><b>Migrante:</b> ${esc(p.migrante==1||p.migrante===true ? "Sí" : (p.migrante===0||p.migrante===false ? "No" : "Sin dato"))}</div>
            <div><b>Género:</b> ${esc(p.genero||"—")}</div>
            <div><b>Sector:</b> ${esc(szName)} / ${esc(scName)}</div>
            <div><b>Coordenadas:</b> ${esc(geo)}</div>
          </div>
        `
      });
    }

    if (type === "familia"){
      const f = resF.find(x => String(x.cod_familia||x.codigo_familia||"") === String(id));
      if (!f) return;

      const { szName, scName } = resolveSector(f);

      await Swal.fire({
        icon: "info",
        title: `Familia ${esc(f.cod_familia || id)}`,
        html: `
          <div style="text-align:left">
            <div><b>Apellido:</b> ${esc(f.apellido_familia||"—")}</div>
            <div><b>Dirección:</b> ${esc(f.direccion||"—")}</div>
            <div><b>Sector:</b> ${esc(szName)} / ${esc(scName)}</div>
            <div><b>Integrantes:</b> ${esc(Number(f.total_integrantes ?? 0))}</div>
          </div>
        `
      });
    }

    if (type === "vivienda"){
      const v = resV.find(x => String(x.cod_vivienda||x.codigo_vivienda||x.cod||x.id||"") === String(id));
      if (!v) return;

      const { szName, scName } = resolveSector(v);

      await Swal.fire({
        icon: "info",
        title: `Vivienda ${esc(id)}`,
        html: `
          <div style="text-align:left">
            <div><b>Dirección:</b> ${esc(v.direccion||"—")}</div>
            <div><b>Sector:</b> ${esc(szName)} / ${esc(scName)}</div>
            <div><b>Tipo:</b> ${esc(v.tipo_vivienda||v.tipo||"—")}</div>
            <div><b>Tenencia:</b> ${esc(v.tenencia||"—")}</div>
          </div>
        `
      });
    }
  }

  document.addEventListener("click", async (e) => {
    const btn = e.target.closest("[data-act]");
    if (!btn) return;

    const act = btn.dataset.act;
    const type = btn.dataset.type;
    const id = btn.dataset.id;

    if (!type || !id) return;

    if (act === "open"){
      rememberSelection(type, id);
      if (type === "persona") window.location.href = "personas.html";
      if (type === "familia") window.location.href = "familias.html";
      if (type === "vivienda") window.location.href = "vivienda.html";
    }

    if (act === "geo"){
      rememberSelection(type, id);
      window.location.href = "geolocalizacion.html";
    }

    if (act === "view"){
      await viewDetail(type, id);
    }
  });

  // ===== Backend apply =====
  let reqId = 0;

  async function applyAsync(showToast = false){
    const F = filters();

    // si desmarcan todo, no consultamos
    const anyType = F.types.p || F.types.f || F.types.v;
    if (!anyType){
      resP = []; resF = []; resV = [];
      renderAll();
      return;
    }

    const my = ++reqId;

    try {
      const payload = {
        q: F.q,
        types: F.types,
        sz: F.sz,
        sec: F.sec,
        inscrito: F.inscrito,
        percapitado: F.percapitado,
        migrante: F.migrante,
        genero: F.genero,
        geo: F.geo
      };

      const r = await fetchJSON(API_BUSQUEDA, {
        method: "POST",
        body: JSON.stringify(payload)
      });

      if (my !== reqId) return; // ignora respuestas viejas

      baseAll = r?.base?.all ?? baseAll;
      if (baseAll != null) lblTotalBase.textContent = `${Number(baseAll)} registros`;
      else lblTotalBase.textContent = "—";

      resP = Array.isArray(r?.data?.p) ? r.data.p : [];
      resF = Array.isArray(r?.data?.f) ? r.data.f : [];
      resV = Array.isArray(r?.data?.v) ? r.data.v : [];

      renderAll();

      if (showToast) {
        await Swal.fire({ icon:"success", title:"Datos recargados", timer: 900, showConfirmButton:false });
      }
    } catch (e) {
      if (my !== reqId) return;
      await Swal.fire({ icon:"error", title:"Error", text: String(e?.message || e) });
    }
  }

  // ===== Events =====
  const applyDebounced = debounce(() => { syncMobileFromDesktop(); applyAsync(false); }, 250);

  // desktop
  q.addEventListener("input", applyDebounced);
  tPersonas.addEventListener("change", applyDebounced);
  tFamilias.addEventListener("change", applyDebounced);
  tViviendas.addEventListener("change", applyDebounced);

  // Sectorización -> actualiza lista de sectores antes de aplicar filtro
  fSz.addEventListener("change", () => {
    populateSectoresSelectsFrom(fSz.value || "");
    applyDebounced();
  });

  fSec.addEventListener("change", applyDebounced);
  fInscrito.addEventListener("change", applyDebounced);
  fPercapitado.addEventListener("change", applyDebounced);
  fMigrante.addEventListener("change", applyDebounced);
  fGenero.addEventListener("change", applyDebounced);
  fGeo.addEventListener("change", applyDebounced);

  btnClearQ.addEventListener("click", () => { q.value = ""; applyDebounced(); });

  btnAplicar.addEventListener("click", () => { syncMobileFromDesktop(); applyAsync(false); });

  btnReset.addEventListener("click", () => {
    q.value = "";
    tPersonas.checked = true;
    tFamilias.checked = true;
    tViviendas.checked = true;

    fSz.value = "";
    populateSectoresSelectsFrom(""); // vuelve a "todos"
    fSec.value = "";

    fInscrito.value = "";
    fPercapitado.value = "";
    fMigrante.value = "";
    fGenero.value = "";
    fGeo.value = "";
    syncMobileFromDesktop();
    applyAsync(false);
  });

  // mobile
  btnClearQM.addEventListener("click", () => { qM.value = ""; });

  // En mobile, al cambiar sectorización, actualiza sectores dentro del offcanvas
  fSzM.addEventListener("change", () => {
    populateSectoresSelectsFrom(fSzM.value || "");
  });

  btnAplicarM.addEventListener("click", () => {
    syncDesktopFromMobile();
    applyAsync(false);
  });

  btnResetM.addEventListener("click", () => {
    qM.value = "";
    tPersonasM.checked = true;
    tFamiliasM.checked = true;
    tViviendasM.checked = true;

    fSzM.value = "";
    populateSectoresSelectsFrom("");
    fSecM.value = "";

    fInscritoM.value = "";
    fPercapitadoM.value = "";
    fMigranteM.value = "";
    fGeneroM.value = "";
    fGeoM.value = "";
    syncDesktopFromMobile();
    applyAsync(false);
  });

  btnRecargar.addEventListener("click", async () => {
    await applyAsync(true);
  });

  // ===== Init =====
  async function init(){
    wireAccordions();
    await loadCatalogs();
    syncMobileFromDesktop();
    applyAsync(false);
  }

  init();
})();
