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

  const API_FAM_LIST = "../php/familias/list.php";
  const API_INSTR = "../php/instrumentos";

  async function fetchJSON(url, options = {}) {
    const res = await fetch(url, {
      credentials: "same-origin",
      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 today() {
    return new Date().toISOString().slice(0, 10);
  }

  function esc(str) {
    return String(str ?? "")
      .replaceAll("&", "&amp;")
      .replaceAll("<", "&lt;")
      .replaceAll(">", "&gt;")
      .replaceAll('"', "&quot;")
      .replaceAll("'", "&#039;");
  }

  function setBadge(el, text, cls) {
    if (!el) return;
    el.textContent = text;
    el.className = cls;
  }

  function setEstado(text, type = "light") {
    const el = $("lblEstado");
    if (!el) return;
    el.textContent = text;
    el.className = `badge text-bg-${type} border`;
  }

  function showTab(name) {
    const tabEl = document.querySelector(`#tab-${name}`);
    if (!tabEl || !window.bootstrap?.Tab) return;
    new bootstrap.Tab(tabEl).show();
  }

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

  function valOf(el) {
    return (el && typeof el.value !== "undefined") ? String(el.value || "").trim() : "";
  }

  function isSelect(el) {
    return el && el.tagName === "SELECT";
  }

  function notifyOk(msg) {
    if (window.Swal?.fire) {
      Swal.fire({ icon: "success", title: "Listo", text: msg, timer: 1400, showConfirmButton: false });
    } else {
      // sin dependencia
      console.log(msg);
    }
  }

  function notifyErr(msg) {
    if (window.Swal?.fire) {
      Swal.fire({ icon: "error", title: "Error", text: msg });
    } else {
      console.error(msg);
      alert(msg);
    }
  }

  /* =========================
     DOM refs (según tu HTML)
  ========================== */
  const famCodigoSearch = $("famCodigoSearch");
  const famApellidoSearch = $("famApellidoSearch");
  const btnBuscarFamilia = $("btnBuscarFamilia");
  const btnQuitarFamilia = $("btnQuitarFamilia");
  const familiasResultados = $("familiasResultados");
  const familiaSeleccionada = $("familiaSeleccionada");
  const integrantesBody = $("integrantesBody");
  const badgeModo = $("badgeModo");
  const btnLimpiarTodo = $("btnLimpiarTodo");
  const btnRecargarHist = $("btnRecargarHist");

  // APGAR
  const apgarFecha = $("apgarFecha");
  const apgarRespondiente = $("apgarRespondiente");
  const apgarQ = [$("apgarQ1"), $("apgarQ2"), $("apgarQ3"), $("apgarQ4"), $("apgarQ5")];
  const apgarTotal = $("apgarTotal");
  const apgarClasif = $("apgarClasif");
  const apgarObs = $("apgarObs");
  const btnLimpiarApgar = $("btnLimpiarApgar");
  const btnGuardarApgar = $("btnGuardarApgar");

  // Línea de tiempo
  const btnAddLT = $("btnAddLT");
  const btnLimpiarLT = $("btnLimpiarLT");
  const btnGuardarLT = $("btnGuardarLT");
  const ltBody = $("ltBody");

  // Ciclo vida
  const cvFecha = $("cvFecha");
  const cvEtapa = $("cvEtapa");
  const cvObs = $("cvObs");
  const btnLimpiarCV = $("btnLimpiarCV");
  const btnGuardarCV = $("btnGuardarCV");

  // Genograma
  const gA = $("gA");
  const gTipo = $("gTipo");
  const gB = $("gB");
  const btnAddRel = $("btnAddRel");
  const gRelList = $("gRelList");
  const btnLimpiarGen = $("btnLimpiarGen");
  const btnGuardarGen = $("btnGuardarGen");

  // Historial
  const instHistBody = $("instHistBody");

  /* =========================
     Estado
  ========================== */
  const state = {
    codigo_familia: null,
    familia: null,
    integrantes: [],
    gen_relaciones: [], // {rut_a,rut_b,tipo}
  };

  /* =========================
     Render: resultados familias
  ========================== */
  function renderFamiliasResultados(rows) {
    if (!familiasResultados) return;

    if (!rows || rows.length === 0) {
      familiasResultados.innerHTML =
        `<div class="text-muted small p-2">Sin resultados. Prueba con otro código o apellido.</div>`;
      return;
    }

    familiasResultados.innerHTML = rows
      .map((r) => {
        const cod = esc(r.codigo_familia);
        const ap = esc(r.apellido_familia || "(sin apellido)");
        const sz = esc(r.nombre_sectorizacion || "");
        const sc = esc(r.nombre_sector || "");
        const tot = esc(r.total_integrantes ?? "0");
        const dir = esc((r.direccion || "").slice(0, 80));
        return `
          <button type="button"
            class="list-group-item list-group-item-action d-flex justify-content-between align-items-start gap-2"
            data-cod="${cod}">
            <div class="me-auto">
              <div class="fw-semibold">${ap} <span class="text-muted">(${cod})</span></div>
              <div class="small text-muted">${sz}${sz && sc ? " · " : ""}${sc}${dir ? " · " + dir : ""}</div>
            </div>
            <span class="badge text-bg-light border">${tot}</span>
          </button>
        `;
      })
      .join("");

    // click select
    familiasResultados.querySelectorAll("button[data-cod]").forEach((btn) => {
      btn.addEventListener("click", () => selectFamilia(btn.dataset.cod));
    });
  }

  /* =========================
     Render: familia seleccionada + integrantes
  ========================== */
  function renderFamiliaSeleccionada() {
    if (!familiaSeleccionada) return;

    if (!state.familia) {
      familiaSeleccionada.innerHTML = `<div class="text-muted small">Aún no has seleccionado una familia.</div>`;
      return;
    }

    const f = state.familia;
    const cod = esc(f.codigo_familia);
    const ap = esc(f.apellido_familia || "(sin apellido)");
    const dir = esc(f.direccion || "");
    const sz = esc(f.nombre_sectorizacion || "");
    const sc = esc(f.nombre_sector || "");
    const tot = state.integrantes.length;

    familiaSeleccionada.innerHTML = `
      <div class="p-2">
        <div class="fw-bold">${ap}</div>
        <div class="small text-muted">Código: <b>${cod}</b></div>
        ${dir ? `<div class="small text-muted">Dirección: ${dir}</div>` : ""}
        <div class="small text-muted">${sz}${sz && sc ? " · " : ""}${sc}</div>
        <div class="mt-2 small">
          <span class="badge text-bg-light border">Integrantes: ${tot}</span>
        </div>
      </div>
    `;
  }

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

    if (!state.codigo_familia) {
      integrantesBody.innerHTML =
        `<tr><td colspan="4" class="text-muted small py-3">Selecciona una familia para cargar integrantes.</td></tr>`;
      return;
    }

    if (!state.integrantes || state.integrantes.length === 0) {
      integrantesBody.innerHTML =
        `<tr><td colspan="4" class="text-muted small py-3">La familia no tiene integrantes asociados en usuarios.</td></tr>`;
      return;
    }

    integrantesBody.innerHTML = state.integrantes
      .map((p) => {
        const rut = esc(p.rut);
        const nom = esc(`${p.apellidos || ""} ${p.nombres || ""}`.trim() || "(sin nombre)");
        const par = esc(p.parentezco || "");
        return `
          <tr>
            <td>
              <button class="btn btn-sm btn-outline-primary" title="Usar como respondiente" data-rut="${rut}">
                <i class="bi bi-check2"></i>
              </button>
            </td>
            <td>${nom}</td>
            <td class="text-muted">${rut}</td>
            <td class="text-muted">${par}</td>
          </tr>
        `;
      })
      .join("");

    // botón "usar"
    integrantesBody.querySelectorAll("button[data-rut]").forEach((b) => {
      b.addEventListener("click", () => {
        if (apgarRespondiente) apgarRespondiente.value = b.dataset.rut;
        setEstado("Respondiente seleccionado", "primary");
      });
    });

    // rellenar selects asociados (solo si son SELECT)
    fillSelectIntegrantes(apgarRespondiente, true);
    fillSelectIntegrantes(gA, false);
    fillSelectIntegrantes(gB, false);
  }

  function fillSelectIntegrantes(sel, includeEmpty) {
    if (!sel || !isSelect(sel)) return;

    const current = sel.value;

    const opts = [];
    opts.push(`<option value="">${includeEmpty ? "Selecciona integrante…" : "Seleccionar…"}</option>`);

    for (const p of state.integrantes) {
      const rut = esc(p.rut);
      const label = esc(`${p.apellidos || ""} ${p.nombres || ""}`.trim() || p.rut);
      opts.push(`<option value="${rut}">${label} (${rut})</option>`);
    }

    sel.innerHTML = opts.join("");
    sel.value = current || "";
  }

  /* =========================
     APGAR: cálculo + render
  ========================== */
  function calcApgar() {
    const vals = apgarQ.map((s) => parseInt(s?.value ?? "0", 10) || 0);
    const total = vals.reduce((a, b) => a + b, 0);
    if (apgarTotal) apgarTotal.textContent = String(total);

    let clas = "Disfunción severa";
    let cls = "badge text-bg-danger mt-2";
    if (total >= 7) {
      clas = "Buena funcionalidad";
      cls = "badge text-bg-success mt-2";
    } else if (total >= 4) {
      clas = "Disfunción moderada";
      cls = "badge text-bg-warning mt-2";
    }

    if (apgarClasif) {
      apgarClasif.textContent = clas;
      apgarClasif.className = cls;
    }
  }

  function setApgarFromData(d) {
    if (!d) return;
    if (apgarFecha) apgarFecha.value = d.fecha_aplicacion || "";
    if (apgarRespondiente) apgarRespondiente.value = d.rut_respondiente || "";
    if (apgarQ[0]) apgarQ[0].value = String(d.q1 ?? 0);
    if (apgarQ[1]) apgarQ[1].value = String(d.q2 ?? 0);
    if (apgarQ[2]) apgarQ[2].value = String(d.q3 ?? 0);
    if (apgarQ[3]) apgarQ[3].value = String(d.q4 ?? 0);
    if (apgarQ[4]) apgarQ[4].value = String(d.q5 ?? 0);
    if (apgarObs) apgarObs.value = d.observaciones || "";
    calcApgar();
  }

  function clearApgar() {
    if (apgarFecha) apgarFecha.value = today();
    if (apgarRespondiente) apgarRespondiente.value = "";
    apgarQ.forEach((s) => s && (s.value = "2"));
    if (apgarObs) apgarObs.value = "";
    calcApgar();
  }

  async function guardarApgar() {
    if (!state.codigo_familia) {
      setEstado("Selecciona una familia primero", "warning");
      showTab("familia");
      return;
    }

    const payload = {
      codigo_familia: state.codigo_familia,
      fecha_aplicacion: valOf(apgarFecha),
      rut_respondiente: normalizeRut(valOf(apgarRespondiente)),
      q1: parseInt(apgarQ[0]?.value ?? "0", 10) || 0,
      q2: parseInt(apgarQ[1]?.value ?? "0", 10) || 0,
      q3: parseInt(apgarQ[2]?.value ?? "0", 10) || 0,
      q4: parseInt(apgarQ[3]?.value ?? "0", 10) || 0,
      q5: parseInt(apgarQ[4]?.value ?? "0", 10) || 0,
      observaciones: valOf(apgarObs),
    };

    try {
      setEstado("Guardando APGAR…", "primary");
      const r = await fetchJSON(`${API_INSTR}/apgar_save.php`, {
        method: "POST",
        body: JSON.stringify(payload),
      });
      calcApgar();
      await recargarHistorial();
      setEstado(`APGAR guardado (Total ${r.total} - ${r.clasificacion})`, "success");
      notifyOk("APGAR guardado.");
    } catch (e) {
      console.error(e);
      setEstado(e.message || "Error guardando APGAR", "danger");
      notifyErr(e.message || "Error guardando APGAR");
    }
  }

  /* =========================
     Línea de tiempo: filas
  ========================== */
  function makeIntegranteSelect() {
    const opts = [`<option value="">(Familia)</option>`];
    for (const p of state.integrantes) {
      const rut = esc(p.rut);
      const label = esc(`${p.apellidos || ""} ${p.nombres || ""}`.trim() || p.rut);
      opts.push(`<option value="${rut}">${label} (${rut})</option>`);
    }
    return `<select class="form-select form-select-sm lt-rut">${opts.join("")}</select>`;
  }

  function addLtRow(ev = {}) {
    if (!ltBody) return;

    // si está placeholder, limpiar
    if (ltBody.querySelector("tr td[colspan]")) ltBody.innerHTML = "";

    const tr = document.createElement("tr");
    tr.dataset.row = "1";

    tr.innerHTML = `
      <td><input type="date" class="form-control form-control-sm lt-fecha" value="${esc(ev.fecha || today())}"></td>
      <td>${makeIntegranteSelect()}</td>
      <td><input class="form-control form-control-sm lt-cat" value="${esc(ev.categoria || "")}" placeholder="Ej: Salud, Duelo..."></td>
      <td><input class="form-control form-control-sm lt-des" value="${esc(ev.descripcion || "")}" placeholder="Descripción breve"></td>
      <td class="text-end">
        <button class="btn btn-sm btn-outline-danger" title="Quitar">
          <i class="bi bi-trash"></i>
        </button>
      </td>
    `;

    ltBody.appendChild(tr);

    // set select value
    const sel = tr.querySelector("select.lt-rut");
    if (sel) sel.value = normalizeRut(ev.rut || "");

    tr.querySelector("button")?.addEventListener("click", () => {
      tr.remove();
      if (!ltBody.querySelector("tr[data-row='1']")) {
        ltBody.innerHTML = `<tr><td colspan="5" class="text-muted small py-3">Aún no hay eventos.</td></tr>`;
      }
    });
  }

  function setLineaFromData(linea) {
    if (!ltBody) return;
    const eventos = linea?.eventos || [];
    if (!eventos.length) {
      ltBody.innerHTML = `<tr><td colspan="5" class="text-muted small py-3">Aún no hay eventos.</td></tr>`;
      return;
    }
    ltBody.innerHTML = "";
    eventos.forEach(addLtRow);
  }

  function clearLinea() {
    if (!ltBody) return;
    ltBody.innerHTML = `<tr><td colspan="5" class="text-muted small py-3">Aún no hay eventos.</td></tr>`;
  }

  function collectLineaEventos() {
    const rows = [...(ltBody?.querySelectorAll("tr[data-row='1']") || [])];
    const out = [];
    for (const tr of rows) {
      const fecha = tr.querySelector(".lt-fecha")?.value?.trim() || "";
      const rut = normalizeRut(tr.querySelector(".lt-rut")?.value || "");
      const categoria = tr.querySelector(".lt-cat")?.value?.trim() || "";
      const descripcion = tr.querySelector(".lt-des")?.value?.trim() || "";

      if (fecha === "" && rut === "" && categoria === "" && descripcion === "") continue;

      out.push({ fecha, rut, categoria, descripcion });
    }
    return out;
  }

  async function guardarLinea() {
    if (!state.codigo_familia) {
      setEstado("Selecciona una familia primero", "warning");
      showTab("familia");
      return;
    }

    const payload = {
      codigo_familia: state.codigo_familia,
      eventos: collectLineaEventos(),
    };

    try {
      setEstado("Guardando Línea de tiempo…", "primary");
      const r = await fetchJSON(`${API_INSTR}/linea_save.php`, {
        method: "POST",
        body: JSON.stringify(payload),
      });

      await recargarHistorial();
      setEstado(`Línea de tiempo guardada (Eventos: ${r.eventos})`, "success");
      notifyOk("Línea de tiempo guardada.");
    } catch (e) {
      console.error(e);
      setEstado(e.message || "Error guardando Línea de tiempo", "danger");
      notifyErr(e.message || "Error guardando Línea de tiempo");
    }
  }

  /* =========================
     Ciclo de vida
  ========================== */
  function setCicloFromData(d) {
    if (!d) return;
    if (cvFecha) cvFecha.value = d.fecha_aplicacion || "";
    if (cvEtapa) cvEtapa.value = d.etapa || "";
    if (cvObs) cvObs.value = d.observaciones || "";
  }

  function clearCiclo() {
    if (cvFecha) cvFecha.value = today();
    if (cvEtapa) cvEtapa.value = "";
    if (cvObs) cvObs.value = "";
  }

  async function guardarCiclo() {
    if (!state.codigo_familia) {
      setEstado("Selecciona una familia primero", "warning");
      showTab("familia");
      return;
    }

    const payload = {
      codigo_familia: state.codigo_familia,
      fecha_aplicacion: valOf(cvFecha),
      etapa: valOf(cvEtapa),
      observaciones: valOf(cvObs),
    };

    try {
      setEstado("Guardando Ciclo…", "primary");
      await fetchJSON(`${API_INSTR}/ciclo_save.php`, {
        method: "POST",
        body: JSON.stringify(payload),
      });

      await recargarHistorial();
      setEstado("Ciclo guardado", "success");
      notifyOk("Ciclo de vida guardado.");
    } catch (e) {
      console.error(e);
      setEstado(e.message || "Error guardando Ciclo", "danger");
      notifyErr(e.message || "Error guardando Ciclo");
    }
  }

  /* =========================
     Genograma: relaciones
  ========================== */
  function renderGenRelaciones() {
    if (!gRelList) return;

    if (!state.gen_relaciones.length) {
      gRelList.innerHTML = `<div class="text-muted small">Aún no hay relaciones.</div>`;
      return;
    }

    gRelList.innerHTML = state.gen_relaciones
      .map((r, idx) => {
        const a = esc(r.rut_a);
        const b = esc(r.rut_b);
        const t = esc(r.tipo);
        const aN = findNombreByRut(r.rut_a);
        const bN = findNombreByRut(r.rut_b);
        return `
          <div class="inst-rel-item d-flex justify-content-between align-items-center gap-2 p-2">
            <div class="small">
              <b>${esc(aN)}</b> <span class="text-muted">(${a})</span>
              <span class="badge text-bg-light border mx-2">${t}</span>
              <b>${esc(bN)}</b> <span class="text-muted">(${b})</span>
            </div>
            <button class="btn btn-sm btn-outline-danger" data-idx="${idx}" title="Quitar">
              <i class="bi bi-x-lg"></i>
            </button>
          </div>
        `;
      })
      .join("");

    gRelList.querySelectorAll("button[data-idx]").forEach((b) => {
      b.addEventListener("click", () => {
        const idx = parseInt(b.dataset.idx, 10);
        if (!Number.isNaN(idx)) state.gen_relaciones.splice(idx, 1);
        renderGenRelaciones();
      });
    });
  }

  function findNombreByRut(rut) {
    const p = state.integrantes.find((x) => x.rut === rut);
    if (!p) return rut || "(sin)";
    return `${p.apellidos || ""} ${p.nombres || ""}`.trim() || rut;
  }

  function setGenogramaFromData(gen) {
    state.gen_relaciones = (gen?.relaciones || [])
      .map((r) => ({
        rut_a: normalizeRut(r.rut_a),
        rut_b: normalizeRut(r.rut_b),
        tipo: String(r.tipo || "").trim(),
      }))
      .filter((x) => x.rut_a && x.rut_b && x.tipo);
    renderGenRelaciones();
  }

  function clearGenograma() {
    if (gA) gA.value = "";
    if (gB) gB.value = "";
    if (gTipo) gTipo.value = "";
    state.gen_relaciones = [];
    renderGenRelaciones();
  }

  function addRelacionFromUI() {
    if (!state.codigo_familia) {
      setEstado("Selecciona una familia primero", "warning");
      showTab("familia");
      return;
    }

    const a = normalizeRut(valOf(gA));
    const b = normalizeRut(valOf(gB));
    const t = valOf(gTipo);

    if (!a || !b || !t) {
      setEstado("Completa A, Tipo y B", "warning");
      return;
    }
    if (a === b) {
      setEstado("A y B no pueden ser el mismo integrante", "warning");
      return;
    }

    // evitar duplicado exacto
    const dup = state.gen_relaciones.some(
      (x) => x.rut_a === a && x.rut_b === b && String(x.tipo) === String(t)
    );
    if (!dup) state.gen_relaciones.push({ rut_a: a, rut_b: b, tipo: t });

    renderGenRelaciones();
    setEstado("Relación agregada", "success");
  }

  async function guardarGenograma() {
    if (!state.codigo_familia) {
      setEstado("Selecciona una familia primero", "warning");
      showTab("familia");
      return;
    }

    const payload = {
      codigo_familia: state.codigo_familia,
      relaciones: state.gen_relaciones.map((r) => ({
        rut_a: normalizeRut(r.rut_a),
        rut_b: normalizeRut(r.rut_b),
        tipo: String(r.tipo || "").trim(),
      })),
    };

    try {
      setEstado("Guardando Genograma…", "primary");
      const r = await fetchJSON(`${API_INSTR}/genograma_save.php`, {
        method: "POST",
        body: JSON.stringify(payload),
      });

      await recargarHistorial();
      setEstado(`Genograma guardado (Relaciones: ${r.relaciones})`, "success");
      notifyOk("Genograma guardado.");
    } catch (e) {
      console.error(e);
      setEstado(e.message || "Error guardando Genograma", "danger");
      notifyErr(e.message || "Error guardando Genograma");
    }
  }

  /* =========================
     Historial
  ========================== */
  function renderHistorial(rows) {
    if (!instHistBody) return;

    if (!state.codigo_familia) {
      instHistBody.innerHTML =
        `<tr><td colspan="6" class="text-muted small py-3">Selecciona una familia para ver historial.</td></tr>`;
      return;
    }

    if (!rows || rows.length === 0) {
      instHistBody.innerHTML =
        `<tr><td colspan="6" class="text-muted small py-3">Aún no hay registros para esta familia.</td></tr>`;
      return;
    }

    instHistBody.innerHTML = rows
      .map((r) => {
        const fecha = esc(r.fecha || "");
        const inst = esc(r.instrumento || "");
        const punt = (r.puntaje === null || r.puntaje === undefined) ? "" : esc(r.puntaje);
        const resu = esc(r.resultado || "");
        const reg = esc(r.registrado_nombre || r.registrado_por || "");
        const refId = esc(r.ref_id);
        const id = esc(r.id);

        return `
        <tr class="align-middle">
          <td class="text-muted small">${fecha}</td>
          <td><span class="badge text-bg-light border">${inst}</span></td>
          <td class="text-muted">${punt}</td>
          <td class="small">${resu}</td>
          <td class="text-muted small">${reg}</td>
          <td class="text-end">
            <button class="btn btn-sm btn-outline-primary"
              data-inst="${inst}"
              data-ref="${refId}"
              data-hid="${id}"
              title="Cargar">
              <i class="bi bi-arrow-up-right-square"></i>
            </button>
          </td>
        </tr>
      `;
      })
      .join("");

    instHistBody.querySelectorAll("button[data-inst]").forEach((b) => {
      b.addEventListener("click", async () => {
        const inst = b.dataset.inst;
        const ref = parseInt(b.dataset.ref, 10);

        try {
          setEstado("Cargando desde historial…", "primary");

          if (inst === "APGAR") {
            showTab("apgar");
            const d = await fetchJSON(`${API_INSTR}/apgar_get.php?id=${ref}`);
            setApgarFromData(d.data);
          } else if (inst === "CICLO_VIDA") {
            showTab("ciclo");
            const d = await fetchJSON(`${API_INSTR}/ciclo_get.php?id=${ref}`);
            setCicloFromData(d.data);
          } else if (inst === "LINEA_TIEMPO") {
            showTab("linea");
            const d = await fetchJSON(`${API_INSTR}/linea_get.php?id=${ref}`);
            setLineaFromData(d.data);
          } else if (inst === "GENOGRAMA") {
            showTab("geno");
            const d = await fetchJSON(`${API_INSTR}/genograma_get.php?id=${ref}`);
            setGenogramaFromData(d.data);
          }

          setEstado("Listo", "light");
        } catch (e) {
          console.error(e);
          setEstado(e.message || "Error", "danger");
          notifyErr(e.message || "Error cargando desde historial");
        }
      });
    });
  }

  async function recargarHistorial() {
    if (!state.codigo_familia) return renderHistorial([]);
    const r = await fetchJSON(`${API_INSTR}/historial.php?cod=${encodeURIComponent(state.codigo_familia)}`);
    renderHistorial(r.data || []);
  }

  /* =========================
     Selección de familia (context)
  ========================== */
  async function selectFamilia(cod) {
    try {
      setEstado("Cargando familia…", "primary");

      const ctx = await fetchJSON(`${API_INSTR}/context.php?cod=${encodeURIComponent(cod)}`);

      state.codigo_familia = ctx.familia?.codigo_familia || cod;
      state.familia = ctx.familia || null;
      state.integrantes = Array.isArray(ctx.integrantes) ? ctx.integrantes : [];

      setBadge(badgeModo, "Seleccionada", "badge text-bg-success");
      if (btnQuitarFamilia) btnQuitarFamilia.disabled = false;

      renderFamiliaSeleccionada();
      renderIntegrantes();

      // cargar últimos instrumentos
      if (ctx.latest?.apgar) setApgarFromData(ctx.latest.apgar);
      else clearApgar();

      if (ctx.latest?.ciclo) setCicloFromData(ctx.latest.ciclo);
      else clearCiclo();

      if (ctx.latest?.linea) setLineaFromData(ctx.latest.linea);
      else clearLinea();

      if (ctx.latest?.genograma) setGenogramaFromData(ctx.latest.genograma);
      else clearGenograma();

      // historial
      renderHistorial(ctx.historial || []);

      setEstado("Listo", "light");
    } catch (e) {
      console.error(e);
      setEstado(e.message || "Error", "danger");
      notifyErr(e.message || "Error cargando familia");
    }
  }

  function clearAll() {
    state.codigo_familia = null;
    state.familia = null;
    state.integrantes = [];
    state.gen_relaciones = [];

    setBadge(badgeModo, "Sin selección", "badge text-bg-light border");
    if (btnQuitarFamilia) btnQuitarFamilia.disabled = true;

    if (familiaSeleccionada) {
      familiaSeleccionada.innerHTML = `<div class="text-muted small">Aún no has seleccionado una familia.</div>`;
    }

    if (integrantesBody) {
      integrantesBody.innerHTML =
        `<tr><td colspan="4" class="text-muted small py-3">Selecciona una familia para cargar integrantes.</td></tr>`;
    }

    clearApgar();
    clearLinea();
    clearCiclo();
    clearGenograma();
    renderHistorial([]);

    setEstado("Listo", "light");
  }

  /* =========================
     Buscar familias
  ========================== */
  async function buscarFamilias() {
    try {
      const cod = valOf(famCodigoSearch);
      const ap = valOf(famApellidoSearch);

      // arma q priorizando código
      let q = "";
      if (cod) q = cod;
      else if (ap) q = ap;

      if (!q) {
        setEstado("Ingresa código o apellido para buscar", "warning");
        if (familiasResultados) {
          familiasResultados.innerHTML =
            `<div class="text-muted small p-2">Escribe un código o apellido y presiona Buscar.</div>`;
        }
        return;
      }

      setEstado("Buscando familias…", "primary");

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

      const rows = r.data || [];
      renderFamiliasResultados(rows);

      // auto-selección si hay 1
      if (rows.length === 1 && rows[0]?.codigo_familia) {
        await selectFamilia(rows[0].codigo_familia);
      }

      setEstado("Listo", "light");
    } catch (e) {
      console.error(e);
      setEstado(e.message || "Error buscando familias", "danger");
      notifyErr(e.message || "Error buscando familias");
    }
  }

  /* =========================
     Wire events
  ========================== */
  function wireEvents() {
    btnBuscarFamilia?.addEventListener("click", buscarFamilias);

    // Enter en inputs
    [famCodigoSearch, famApellidoSearch].forEach((el) => {
      el?.addEventListener("keydown", (ev) => {
        if (ev.key === "Enter") {
          ev.preventDefault();
          buscarFamilias();
        }
      });
    });

    btnQuitarFamilia?.addEventListener("click", () => {
      clearAll();
      setEstado("Familia quitada", "secondary");
    });

    btnLimpiarTodo?.addEventListener("click", () => {
      if (famCodigoSearch) famCodigoSearch.value = "";
      if (famApellidoSearch) famApellidoSearch.value = "";
      if (familiasResultados) {
        familiasResultados.innerHTML =
          `<div class="text-muted small p-2">Escribe un código o apellido y presiona Buscar.</div>`;
      }
      clearAll();
    });

    btnRecargarHist?.addEventListener("click", async () => {
      try {
        setEstado("Recargando historial…", "primary");
        await recargarHistorial();
        setEstado("Listo", "light");
      } catch (e) {
        console.error(e);
        setEstado(e.message || "Error recargando historial", "danger");
        notifyErr(e.message || "Error recargando historial");
      }
    });

    // APGAR eventos
    apgarQ.forEach((s) => {
      s?.addEventListener("change", calcApgar);
      s?.addEventListener("input", calcApgar);
    });
    btnLimpiarApgar?.addEventListener("click", () => {
      clearApgar();
      setEstado("APGAR limpio", "secondary");
    });
    btnGuardarApgar?.addEventListener("click", guardarApgar);

    // Línea de tiempo eventos
    btnAddLT?.addEventListener("click", () => {
      if (!state.codigo_familia) {
        setEstado("Selecciona una familia primero", "warning");
        return;
      }
      addLtRow({ fecha: today() });
      setEstado("Evento agregado", "secondary");
    });

    btnLimpiarLT?.addEventListener("click", () => {
      clearLinea();
      setEstado("Línea de tiempo limpia", "secondary");
    });

    btnGuardarLT?.addEventListener("click", guardarLinea);

    // Ciclo vida eventos
    btnLimpiarCV?.addEventListener("click", () => {
      clearCiclo();
      setEstado("Ciclo limpio", "secondary");
    });
    btnGuardarCV?.addEventListener("click", guardarCiclo);

    // Genograma eventos
    btnAddRel?.addEventListener("click", addRelacionFromUI);
    btnLimpiarGen?.addEventListener("click", () => {
      clearGenograma();
      setEstado("Genograma limpio", "secondary");
    });
    btnGuardarGen?.addEventListener("click", guardarGenograma);
  }

  /* =========================
     Init
  ========================== */
  function init() {
    setBadge(badgeModo, "Sin selección", "badge text-bg-light border");
    if (btnQuitarFamilia) btnQuitarFamilia.disabled = true;

    if (familiasResultados) {
      familiasResultados.innerHTML =
        `<div class="text-muted small p-2">Escribe un código o apellido y presiona Buscar.</div>`;
    }

    // defaults
    if (apgarFecha && !apgarFecha.value) apgarFecha.value = today();
    if (cvFecha && !cvFecha.value) cvFecha.value = today();

    // placeholders
    if (ltBody && !ltBody.innerHTML.trim()) clearLinea();
    renderGenRelaciones();
    calcApgar();
    renderFamiliaSeleccionada();
    renderIntegrantes();
    renderHistorial([]);

    wireEvents();
    setEstado("Listo", "light");
  }

  document.addEventListener("DOMContentLoaded", init);
})();
