(function (global) {
  const app = (global.EpicrisisApp = global.EpicrisisApp || {});

  function extraerCie10Inline(texto) {
    const value = String(texto || "").trim();
    const match = new RegExp(/^\s*([A-TV-Z]\d{2}(?:\.[0-9A-Z]{1,6}|[0-9A-Z]{1,4})?)\s*(?:[-:]|\s)\s*(.+)$/i).exec(value);
    if (!match) {
      return { codigo: "", descripcion: "" };
    }
    return { codigo: match[1].toUpperCase(), descripcion: match[2].trim() };
  }

  function normalizarCodigoCie10(codigo) {
    const value = String(codigo || "").toUpperCase().replace(/\s+/g, "");
    const match = new RegExp(/^([A-TV-Z]\d{2})(?:\.?([0-9A-Z]{1,6}))?$/).exec(value);
    if (!match) return "";
    const base = match[1];
    const resto = match[2] || "";
    if (!resto) return base;
    const digito = new RegExp(/\d/).exec(resto);
    return `${base}.${digito ? digito[0] : resto[0]}`;
  }

  function limpiarTextoDiagnostico(texto) {
    return String(texto || "").replace(/\s+/g, " ").trim();
  }

  function normalizarDiagnosticoSinCodigo(diagnostico) {
    const limpio = limpiarTextoDiagnostico(diagnostico);
    if (!limpio) return "";
    const inline = extraerCie10Inline(limpio);
    if (inline.codigo) {
      return limpiarTextoDiagnostico(inline.descripcion);
    }
    return limpio;
  }

  function combinarDescripcionYDiagnostico(descripcion, diagnostico) {
    const descripcionLimpia = limpiarTextoDiagnostico(descripcion);
    const diagnosticoLimpio = normalizarDiagnosticoSinCodigo(diagnostico);

    if (descripcionLimpia && diagnosticoLimpio) {
      if (descripcionLimpia.toLowerCase() === diagnosticoLimpio.toLowerCase()) {
        return descripcionLimpia;
      }
      return `${descripcionLimpia}. ${diagnosticoLimpio}`;
    }

    return descripcionLimpia || diagnosticoLimpio;
  }

  function formatearDiagnosticoPresentacion(item) {
    const codigo = limpiarTextoDiagnostico(item?.codigo || item?.codigo_asignado || "").toUpperCase();
    const descripcion = limpiarTextoDiagnostico(item?.descripcion || "");
    const diagnostico = limpiarTextoDiagnostico(item?.diagnostico || "");
    const detalle = combinarDescripcionYDiagnostico(descripcion, diagnostico);

    if (codigo && detalle) {
      return `${codigo} - ${detalle}`;
    }
    return codigo || detalle;
  }

  function normalizarDiagnosticosConsolidados(lista) {
    return (lista || [])
      .map((item) => {
        const codigo = limpiarTextoDiagnostico(item?.codigo || "").toUpperCase();
        const descripcion = limpiarTextoDiagnostico(item?.descripcion || item?.diagnostico || "");
        const diagnostico = limpiarTextoDiagnostico(item?.diagnostico || item?.descripcion || "");
        const estado = String(
          item?.estado_codificacion || (codigo ? "codificado" : "pendiente_validacion")
        ).trim() || "pendiente_validacion";
        const textoPresentacion = String(item?.texto_presentacion || "").trim()
          || (codigo ? `${codigo} - ${descripcion || diagnostico}` : `PENDIENTE - ${descripcion || diagnostico}`);
        return {
          ...item,
          key: String(item?.key || "").trim() || textoPresentacion.toLowerCase(),
          codigo,
          descripcion,
          diagnostico,
          estado_codificacion: estado,
          texto_presentacion: textoPresentacion,
          fuentes: Array.isArray(item?.fuentes) ? item.fuentes : [],
        };
      })
      .filter((item) => item.texto_presentacion);
  }

  function normalizarDiagnosticos(lista) {
    return (lista || []).map((item) => {
      const diagnostico = item?.diagnostico || item?.descripcion || "";
      let codigo = item?.codigo || item?.codigo_asignado || "";
      let descripcion = item?.descripcion || "";
      if (!codigo || !descripcion) {
        const inline = extraerCie10Inline(diagnostico);
        if (!codigo && inline.codigo) {
          codigo = inline.codigo;
        }
        if (!descripcion && inline.descripcion) {
          descripcion = inline.descripcion;
        }
      }
      const tipo = (String(diagnostico).toUpperCase().includes("POP") || String(diagnostico).toUpperCase().includes("POST"))
        ? "POST"
        : "PRE";
      return {
        diagnostico,
        tipo,
        codigo: codigo || "",
        descripcion: descripcion || "",
      };
    });
  }

  function construirMapaCie10Canonico() {
    const data = app.state.data;
    const byCode = new Map();
    const byPrefix = new Map();
    const base = [
      ...normalizarDiagnosticos(data.cieHistoria),
      ...normalizarDiagnosticos(data.cieQx),
      ...normalizarDiagnosticosConsolidados(data.diagnosticosConsolidados),
    ];

    base.forEach((item) => {
      const codigoRaw = limpiarTextoDiagnostico(item?.codigo || "").toUpperCase();
      const descripcion = limpiarTextoDiagnostico(item?.descripcion || "");
      const diagnostico = limpiarTextoDiagnostico(item?.diagnostico || "");
      const detalle = combinarDescripcionYDiagnostico(descripcion, diagnostico);
      if (!codigoRaw || !detalle) return;

      const registro = { codigo: codigoRaw, descripcion, diagnostico };
      if (!byCode.has(codigoRaw)) byCode.set(codigoRaw, registro);

      const codigoNorm = normalizarCodigoCie10(codigoRaw);
      if (codigoNorm && !byCode.has(codigoNorm)) byCode.set(codigoNorm, registro);

      const prefijo = codigoRaw.slice(0, 3);
      if (prefijo && !byPrefix.has(prefijo)) byPrefix.set(prefijo, registro);
    });

    return { byCode, byPrefix };
  }

  function parseDiagnosticoParaPdf(texto, mapaCie10Canonico) {
    const value = app.utils.stripHtml(texto).replace(/\s+/g, " ").trim();
    const pendingMatch = value.match(/^\s*PENDIENTE\s*(?:[-:]|\s)\s*(.+)$/i);
    if (pendingMatch) {
      return { codigo: "PENDIENTE", descripcion: pendingMatch[1].trim() };
    }
    const match = value.match(/^\s*([A-TV-Z]\d{2}(?:\.[0-9A-Z]{1,6}|[0-9A-Z]{1,4})?)\s*(?:[-:]|\s)\s*(.+)$/i);
    if (!match) {
      return { codigo: "", descripcion: value };
    }

    const codigoRaw = match[1].toUpperCase();
    const descripcionRaw = match[2].trim();
    const codigoNorm = normalizarCodigoCie10(codigoRaw);
    const prefijo = codigoRaw.slice(0, 3);

    const canonico =
      mapaCie10Canonico.byCode.get(codigoRaw) ||
      (codigoNorm ? mapaCie10Canonico.byCode.get(codigoNorm) : null) ||
      mapaCie10Canonico.byPrefix.get(prefijo);

    if (canonico) {
      const descripcionCanonica = combinarDescripcionYDiagnostico(canonico.descripcion, canonico.diagnostico);
      return {
        codigo: canonico.codigo || codigoNorm || codigoRaw,
        descripcion: descripcionCanonica || descripcionRaw,
      };
    }

    return {
      codigo: codigoNorm || codigoRaw,
      descripcion: descripcionRaw,
    };
  }

  app.diagnosticos = {
    extraerCie10Inline,
    normalizarCodigoCie10,
    limpiarTextoDiagnostico,
    normalizarDiagnosticoSinCodigo,
    combinarDescripcionYDiagnostico,
    formatearDiagnosticoPresentacion,
    normalizarDiagnosticosConsolidados,
    normalizarDiagnosticos,
    construirMapaCie10Canonico,
    parseDiagnosticoParaPdf,
  };
})(globalThis);
