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

  const API_FAMILIAS = "../php/familias";
  const API_SECTORIZACION = "../php/config/sectorizacion";
  const API_SECTORES = "../php/config/sectores";
  const API_PERSONAS = "../php/personas";

  const today = () => new Date().toISOString().slice(0, 10);

  const esc = (s) =>
    String(s ?? "").replace(/[&<>"']/g, (m) => ({
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      '"': "&quot;",
      "'": "&#39;"
    }[m]));

  function debounce(fn, wait = 350) {
    let t = null;
    return (...args) => {
      clearTimeout(t);
      t = setTimeout(() => fn(...args), wait);
    };
  }

  function normRut(rut) {
    return String(rut ?? "")
      .toUpperCase()
      .replace(/[^0-9K]/g, "")
      .slice(0, 15);
  }

  async function fetchJSON(url, options = {}) {
    const res = await fetch(url, {
      credentials: "same-origin",
      cache: "no-store",
      headers: { "Content-Type": "application/json" },
      ...options
    });

    const text = await res.text().catch(() => "");
    let data = null;
    try {
      data = text ? JSON.parse(text) : null;
    } catch {
      data = null;
    }

    if (!res.ok || !data || data.ok === false) {
      const msg = data?.message || "Error de servidor";
      const err = new Error(msg);
      err.status = res.status;
      err.url = url;
      err.body = text;
      throw err;
    }

    return data;
  }

  function showFetchError(title, err) {
    console.error("[familias] error:", {
      url: err?.url,
      status: err?.status,
      message: err?.message,
      body: err?.body
    });

    Swal.fire({
      icon: "error",
      title: title || "Error",
      text: err?.message || "Error de servidor"
    });
  }

  /* =========================
     DOM
  ========================== */
  // Form
  const cod_familia = $("cod_familia");
  const apellido_familia = $("apellido_familia");
  const fecha_evaluacion = $("fecha_evaluacion");
  const sectorizacion = $("sectorizacion");
  const sector = $("sector");
  const direccion = $("direccion");

  // Integrantes
  const rut_integrante = $("rut_integrante");
  const personaPreview = $("personaPreview");
  const integrantesList = $("integrantesList");
  const lblIntegrantes = $("lblIntegrantes");
  const btnAddIntegrante = $("btnAddIntegrante");

  // Clasificación
  const tipo_familia = $("tipo_familia");
  const etapa_ciclo_familia = $("etapa_ciclo_familia");
  const puntaje_riesgo = $("puntaje_riesgo");
  const clasificacion_riesgo = $("clasificacion_riesgo");

  // Botones
  const btnGuardar = $("btnGuardar");
  const btnEliminar = $("btnEliminar");
  const btnNuevo = $("btnNuevo");
  const btnCancelar = $("btnCancelar");
  const btnGenCodigo = $("btnGenCodigo");

  // Listado
  const qList = $("qList");
  const resultsList = $("resultsList");
  const lblTotal = $("lblTotal");
  const lblCount = $("lblCount");
  const lblEstado = $("lblEstado");

  // Filtros del listado (panel derecho)
  const fSz = $("fSz");
  const fSec = $("fSec");
  const btnAplicarList = $("btnAplicarList");
  const btnResetList = $("btnResetList");
  const btnRefrescarList = $("btnRefrescarList");

  /* =========================
     Estado
  ========================== */
  let familias = [];
  let currentCod = null;
  let integrantes = [];
  let cacheSectores = [];
  let cacheSectorizaciones = [];

  /* =========================
     Sectorización / Sector
  ========================== */
  async function loadSectorizacion() {
    const { data } = await fetchJSON(`${API_SECTORIZACION}/list.php`);
    cacheSectorizaciones = Array.isArray(data) ? data : [];

    // Form select
    if (sectorizacion) {
      sectorizacion.innerHTML = `<option value="">Seleccionar</option>`;
      cacheSectorizaciones.forEach((s) => {
        sectorizacion.insertAdjacentHTML(
          "beforeend",
          `<option value="${esc(s.id)}">${esc(s.nombre_sectorizacion)}</option>`
        );
      });
    }

    // Filtro listado
    if (fSz) {
      fSz.innerHTML = `<option value="">Todas</option>`;
      cacheSectorizaciones.forEach((s) => {
        fSz.insertAdjacentHTML(
          "beforeend",
          `<option value="${esc(s.id)}">${esc(s.nombre_sectorizacion)}</option>`
        );
      });
    }
  }

  async function loadSectoresAllOnce() {
    if (cacheSectores.length) return;
    const { data } = await fetchJSON(`${API_SECTORES}/list.php`);
    cacheSectores = Array.isArray(data) ? data : [];
  }

  async function loadSectoresBySectorizacion(id = "", targetSelect) {
    await loadSectoresAllOnce();

    const sel = targetSelect;
    if (!sel) return;

    const emptyLabel = sel === sector ? "Seleccionar" : "Todos";
    sel.innerHTML = `<option value="">${emptyLabel}</option>`;

    cacheSectores
      .filter((s) => !id || String(s.sectorizacion) === String(id))
      .forEach((s) => {
        sel.insertAdjacentHTML(
          "beforeend",
          `<option value="${esc(s.id)}">${esc(s.nombre_sector)}</option>`
        );
      });
  }

  // Cambia sectorización (form)
  sectorizacion?.addEventListener("change", async () => {
    await loadSectoresBySectorizacion(sectorizacion.value, sector);
    if (sector) sector.value = "";
    if (cod_familia) cod_familia.value = "";
  });

  // Cambia sectorización (filtro listado)
  fSz?.addEventListener("change", async () => {
    await loadSectoresBySectorizacion(fSz.value, fSec);
    if (fSec) fSec.value = "";
  });

  /* =========================
     Código familia (next_code.php)
  ========================== */
  btnGenCodigo?.addEventListener("click", async () => {
    try {
      if (!sectorizacion?.value || !sector?.value) {
        Swal.fire("Atención", "Selecciona sectorización y sector", "warning");
        return;
      }

      const { codigo } = await fetchJSON(
        `${API_FAMILIAS}/next_code.php?sectorizacion=${encodeURIComponent(sectorizacion.value)}&sector=${encodeURIComponent(sector.value)}`
      );

      cod_familia.value = codigo || "";
    } catch (e) {
      showFetchError("No se pudo generar el código", e);
    }
  });

  /* =========================
     Personas (preview)
  ========================== */
   /* =========================
     Personas (preview) ✅ RUT o NOMBRE/APELLIDO (sin bucle con K)
     - Si "parece RUT" (números + . - espacios + K opcional al final) => get.php
     - Si tiene letras y NO parece RUT => list.php con sugerencias
  ========================== */

  function isRutLike(raw) {
    const t = String(raw ?? "").trim();
    if (!t) return false;

    // Debe tener al menos 1 dígito para considerarlo "rut"
    if (!/\d/.test(t)) return false;

    // Permite: 12.345.678-5 / 123456785 / 12 345 678 K / 12345678-K
    // Solo dígitos, puntos, guiones, espacios, y K opcional al FINAL.
    return /^[0-9.\-\s]+[0-9Kk]?$/.test(t);
  }

  const previewPersona = debounce(async () => {
    if (!rut_integrante) return;

    const raw = String(rut_integrante.value ?? "").trim();

    // vacío
    if (!raw) {
      if (personaPreview) personaPreview.textContent = "Ingresa un RUT o un nombre/apellido.";
      return;
    }

    const rutLike = isRutLike(raw);
    const hasLetters = /[A-Za-zÁÉÍÓÚÜÑáéíóúüñ]/u.test(raw);

    // =========================
    // MODO NOMBRE/APELLIDO (solo si NO parece RUT)
    // =========================
    if (!rutLike && hasLetters) {
      if (raw.length < 2) {
        if (personaPreview) personaPreview.textContent = "Escribe al menos 2 letras para buscar por nombre.";
        return;
      }

      try {
        const resp = await fetchJSON(`${API_PERSONAS}/list.php`, {
          method: "POST",
          body: JSON.stringify({
            q: raw,
            limit: 8,
            offset: 0
          })
        });

        const rows = Array.isArray(resp.data) ? resp.data : [];

        if (!rows.length) {
          if (personaPreview) personaPreview.textContent = "Sin coincidencias.";
          return;
        }

        // Render sugerencias clickeables dentro de personaPreview (sin tocar HTML)
        const html = `
          <div class="small text-muted mb-1">Selecciona una persona:</div>
          <div class="list-group">
            ${rows.map(p => {
              const nom = `${p.nombres ?? ""} ${p.apellidos ?? ""}`.trim();
              const r = String(p.rut ?? "").trim();
              return `
                <button type="button"
                        class="list-group-item list-group-item-action py-1"
                        data-pick-rut="${esc(r)}">
                  <div><b>${esc(nom || r)}</b></div>
                  <div class="small text-muted">RUT: ${esc(r)}</div>
                </button>
              `;
            }).join("")}
          </div>
        `;

        if (personaPreview) personaPreview.innerHTML = html;
      } catch {
        if (personaPreview) personaPreview.textContent = "Error buscando por nombre.";
      }

      return; // 👈 importante: no seguir al modo RUT
    }

    // =========================
    // MODO RUT (incluye K al final)
    // =========================
    const rut = normRut(raw);
    // OJO: asignar value NO dispara input (así evitamos bucle)
    rut_integrante.value = rut;

    if (!rut) {
      if (personaPreview) personaPreview.textContent = "Ingresa un RUT o un nombre/apellido.";
      return;
    }

    if (rut.length < 7) {
      if (personaPreview) personaPreview.textContent = "Ingresa un RUT válido.";
      return;
    }

    try {
      const { data } = await fetchJSON(`${API_PERSONAS}/get.php?rut=${encodeURIComponent(rut)}`);
      const nom = `${data?.nombres ?? ""} ${data?.apellidos ?? ""}`.trim();
      if (personaPreview) personaPreview.innerHTML = `<b>${esc(nom || rut)}</b>`;
    } catch {
      if (personaPreview) personaPreview.textContent = "No encontrada.";
    }
  }, 350);

  // input en RUT persona (pero ahora acepta también nombre/apellido)
  rut_integrante?.addEventListener("input", previewPersona);

  // click en una sugerencia (si buscó por nombre)
  personaPreview?.addEventListener("click", (e) => {
    const b = e.target.closest("[data-pick-rut]");
    if (!b) return;

    const picked = normRut(b.getAttribute("data-pick-rut") || "");
    if (!picked) return;

    rut_integrante.value = picked;

    // fuerza refrescar preview (modo RUT) y evita quedarse con la lista
    previewPersona();
    rut_integrante.focus();
  });

  /* =========================
     Integrantes (chips) ✅
  ========================== */

  btnAddIntegrante?.addEventListener("click", () => {
    if (!rut_integrante) return;

    const raw = String(rut_integrante.value ?? "").trim();
    const rutLike = isRutLike(raw);
    const hasLetters = /[A-Za-zÁÉÍÓÚÜÑáéíóúüñ]/u.test(raw);

    // Si está en modo nombre (letras y NO parece rut), no se agrega directo
    if (!rutLike && hasLetters) {
      Swal.fire("Atención", "Selecciona una persona de la lista para obtener su RUT.", "warning");
      return;
    }

    const rut = normRut(raw);
    if (!rut || rut.length < 7) {
      Swal.fire("Atención", "Ingresa un RUT válido o busca por nombre y selecciona una persona.", "warning");
      return;
    }

    if (!integrantes.includes(rut)) integrantes.push(rut);

    rut_integrante.value = "";
    if (personaPreview) personaPreview.textContent = "";

    renderIntegrantes();
  });

  rut_integrante?.addEventListener("keydown", (e) => {
    if (e.key !== "Enter") return;

    e.preventDefault();

    const raw = String(rut_integrante.value ?? "").trim();
    const rutLike = isRutLike(raw);
    const hasLetters = /[A-Za-zÁÉÍÓÚÜÑáéíóúüñ]/u.test(raw);

    // si está en modo nombre, Enter no agrega (debe seleccionar sugerencia)
    if (!rutLike && hasLetters) return;

    btnAddIntegrante?.click();
  });

  function renderIntegrantes() {
    if (!integrantesList) return;

    integrantesList.innerHTML = "";

    integrantes.forEach((rut, i) => {
      integrantesList.insertAdjacentHTML(
        "beforeend",
        `<div class="chip">
          ${esc(rut)}
          <button data-i="${i}" class="x" type="button" aria-label="Eliminar integrante">
            <i class="bi bi-x-lg"></i>
          </button>
        </div>`
      );
    });

    if (lblIntegrantes) lblIntegrantes.textContent = `Integrantes: ${integrantes.length}`;
  }

  integrantesList?.addEventListener("click", (e) => {
    const b = e.target.closest("[data-i]");
    if (!b) return;

    const idx = Number(b.dataset.i);
    if (Number.isFinite(idx)) {
      integrantes.splice(idx, 1);
      renderIntegrantes();
    }
  });



  /* =========================
     Riesgo automático
  ========================== */
  function computeRiesgo() {
    let total = 0;
    document.querySelectorAll(".fr:checked").forEach((c) => {
      total += Number(c.dataset.points || 0);
    });

    if (puntaje_riesgo) puntaje_riesgo.value = String(total || "");
    if (clasificacion_riesgo) {
      clasificacion_riesgo.value =
        total >= 20 ? "Alto" :
          total >= 7 ? "Medio" :
            total > 0 ? "Bajo" : "";
    }
  }

  document.querySelectorAll(".fr").forEach((chk) => {
    chk.addEventListener("change", computeRiesgo);
  });

  /* =========================
     Guardar
  ========================== */
  btnGuardar?.addEventListener("click", async () => {
    try {
      const codigo = String(cod_familia?.value ?? "").trim();
      const apellido = String(apellido_familia?.value ?? "").trim();

      if (!codigo || !apellido) {
        Swal.fire("Error", "Código y apellido son obligatorios", "warning");
        return;
      }

      const factores_protectores = [...document.querySelectorAll(".fp-protector:checked")].map(c => c.value);
      const factores_riesgo = [...document.querySelectorAll(".fr:checked")].map(c => c.value);

      await fetchJSON(`${API_FAMILIAS}/save.php`, {
        method: "POST",
        body: JSON.stringify({
          codigo_familia: codigo,
          cod_familia: codigo,
          apellido_familia: apellido,
          fecha_evaluacion: fecha_evaluacion?.value || today(),
          sectorizacion: sectorizacion?.value || "",
          sector: sector?.value || "",
          direccion: direccion?.value || "",
          integrantes: integrantes.slice(),
          clasificacion: {
            tipo_familia: tipo_familia?.value || "",
            etapa_ciclo_familia: etapa_ciclo_familia?.value || "",
            factores_protectores,
            factores_riesgo,
            puntaje_riesgo: puntaje_riesgo?.value || "",
            clasificacion_riesgo: clasificacion_riesgo?.value || ""
          }
        })
      });

      Swal.fire("OK", "Familia guardada", "success");
      resetForm();
      await loadFamilias();
    } catch (e) {
      showFetchError("No se pudo guardar la familia", e);
    }
  });

  /* =========================
     Eliminar
  ========================== */
  btnEliminar?.addEventListener("click", async () => {
    try {
      if (!currentCod) return;

      const r = await Swal.fire({
        icon: "warning",
        title: "¿Eliminar familia?",
        text: currentCod,
        showCancelButton: true,
        confirmButtonText: "Sí, eliminar",
        cancelButtonText: "Cancelar"
      });
      if (!r.isConfirmed) return;

      await fetchJSON(`${API_FAMILIAS}/delete.php`, {
        method: "POST",
        body: JSON.stringify({ codigo_familia: currentCod, cod_familia: currentCod, cod: currentCod })
      });

      resetForm();
      await loadFamilias();
      Swal.fire("OK", "Familia eliminada", "success");
    } catch (e) {
      showFetchError("No se pudo eliminar la familia", e);
    }
  });

  /* =========================
     Listado (list.php)
  ========================== */
  async function loadFamilias() {
    const payload = {
      q: String(qList?.value ?? "").trim(),
      sectorizacion: String(fSz?.value ?? "").trim(),
      sector: String(fSec?.value ?? "").trim()
    };

    const { data, total, filtered_total } = await fetchJSON(`${API_FAMILIAS}/list.php`, {
      method: "POST",
      body: JSON.stringify(payload)
    });

    familias = Array.isArray(data) ? data : [];
    if (lblTotal) lblTotal.textContent = String(filtered_total ?? total ?? familias.length ?? 0);

    renderList(familias);
  }

  function renderList(arr) {
    if (!resultsList) return;
    resultsList.innerHTML = "";

    if (lblCount) lblCount.textContent = `Coincidencias: ${arr.length}`;

    arr.forEach((f) => {
      const codigo = f.codigo_familia ?? f.cod_familia ?? "";
      const apellido = f.apellido_familia ?? "";
      const nomSz = f.nombre_sectorizacion ?? "";
      const nomSec = f.nombre_sector ?? "";
      const totalInt = f.total_integrantes ?? f.integrantes_total ?? f.cant_integrantes ?? "";

      resultsList.insertAdjacentHTML(
        "beforeend",
        `<div class="result-item" data-cod="${esc(codigo)}">
          <div class="name"><b>${esc(codigo)}</b> · ${esc(apellido)}</div>
          <div class="meta">
            ${nomSz ? `<span class="badge text-bg-light">${esc(nomSz)}</span>` : ""}
            ${nomSec ? `<span class="badge text-bg-light">${esc(nomSec)}</span>` : ""}
            ${totalInt !== "" ? `<span class="badge text-bg-light">Integrantes: ${esc(totalInt)}</span>` : ""}
          </div>
        </div>`
      );
    });
  }

  // filtros
  btnAplicarList?.addEventListener("click", async () => {
    try {
      await loadFamilias();
    } catch (e) {
      showFetchError("No se pudo cargar el listado", e);
    }
  });

  btnResetList?.addEventListener("click", async () => {
    try {
      if (qList) qList.value = "";
      if (fSz) fSz.value = "";
      if (fSec) {
        fSec.value = "";
        await loadSectoresBySectorizacion("", fSec);
      }
      await loadFamilias();
    } catch (e) {
      showFetchError("No se pudo limpiar el filtro", e);
    }
  });

  btnRefrescarList?.addEventListener("click", async () => {
    try {
      await loadFamilias();
    } catch (e) {
      showFetchError("No se pudo refrescar", e);
    }
  });

  // búsqueda live
  qList?.addEventListener("input", debounce(async () => {
    try {
      await loadFamilias();
    } catch (e) {
      showFetchError("No se pudo buscar", e);
    }
  }, 250));

  /* =========================
     Click en listado -> get.php
  ========================== */
  async function fetchFamiliaByCodigo(codigo) {
    const cod = encodeURIComponent(String(codigo || "").trim());

    // IMPORTANTE: tu get.php actual lee $_GET['cod'].
    // Este orden asegura que primero probamos ?cod= (lo que tú usas).
    try {
      return await fetchJSON(`${API_FAMILIAS}/get.php?cod=${cod}`);
    } catch (e1) {
      try {
        return await fetchJSON(`${API_FAMILIAS}/get.php?codigo_familia=${cod}`);
      } catch (e2) {
        return await fetchJSON(`${API_FAMILIAS}/get.php?codigo=${cod}`);
      }
    }
  }

  resultsList?.addEventListener("click", async (e) => {
    const it = e.target.closest("[data-cod]");
    if (!it) return;

    try {
      const resp = await fetchFamiliaByCodigo(it.dataset.cod);
      fillForm(resp.data || {});
    } catch (err) {
      showFetchError("No se pudo cargar la familia", err);
    }
  });

  function setChecks(selector, values) {
    const set = new Set((values || []).map(String));
    document.querySelectorAll(selector).forEach((el) => {
      el.checked = set.has(String(el.value));
    });
  }

  function fillForm(f) {
    const codigo = f.codigo_familia ?? f.cod_familia ?? f.codigo ?? "";
    currentCod = codigo || null;

    if (cod_familia) cod_familia.value = codigo || "";
    if (apellido_familia) apellido_familia.value = f.apellido_familia ?? "";
    if (fecha_evaluacion) fecha_evaluacion.value = f.fecha_evaluacion ?? today();

    if (sectorizacion) sectorizacion.value = String(f.sectorizacion ?? "");
    loadSectoresBySectorizacion(String(f.sectorizacion ?? ""), sector).then(() => {
      if (sector) sector.value = String(f.sector ?? "");
    });

    if (direccion) direccion.value = f.direccion ?? "";

    integrantes = Array.isArray(f.integrantes) ? f.integrantes.map(normRut) : [];
    renderIntegrantes();

    // clasificación
    const c = f.clasificacion || {};
    if (tipo_familia) tipo_familia.value = c.tipo_familia ?? "";
    if (etapa_ciclo_familia) etapa_ciclo_familia.value = c.etapa_ciclo_familia ?? "";
    setChecks(".fp-protector", c.factores_protectores || []);
    setChecks(".fr", c.factores_riesgo || []);
    computeRiesgo();

    if (puntaje_riesgo && (c.puntaje_riesgo ?? "") !== "") puntaje_riesgo.value = String(c.puntaje_riesgo);
    if (clasificacion_riesgo && (c.clasificacion_riesgo ?? "") !== "") clasificacion_riesgo.value = String(c.clasificacion_riesgo);

    if (btnEliminar) btnEliminar.disabled = false;
    if (lblEstado) lblEstado.textContent = `Editando ${codigo}`;
  }

  function resetChecks() {
    document.querySelectorAll(".fp-protector, .fr").forEach((el) => (el.checked = false));
    computeRiesgo();
  }

  function resetForm() {
    currentCod = null;
    integrantes = [];

    if (cod_familia) cod_familia.value = "";
    if (apellido_familia) apellido_familia.value = "";
    if (fecha_evaluacion) fecha_evaluacion.value = today();
    if (sectorizacion) sectorizacion.value = "";
    if (sector) sector.value = "";
    if (direccion) direccion.value = "";

    if (rut_integrante) rut_integrante.value = "";
    if (personaPreview) personaPreview.textContent = "";

    resetChecks();
    renderIntegrantes();

    if (btnEliminar) btnEliminar.disabled = true;
    if (lblEstado) lblEstado.textContent = "Nuevo registro";
  }

  btnNuevo?.addEventListener("click", resetForm);
  btnCancelar?.addEventListener("click", resetForm);

  /* =========================
     Init
  ========================== */
  (async () => {
    try {
      if (fecha_evaluacion) fecha_evaluacion.value = today();

      await loadSectorizacion();
      await loadSectoresBySectorizacion("", sector);
      await loadSectoresBySectorizacion("", fSec);

      resetForm();
      await loadFamilias();
    } catch (e) {
      showFetchError("Error inicializando Familias", e);
    }
  })();
})();
