// src/screen-relaciones.jsx — Pólizas relacionadas (capacidad GENÉRICA de la ficha).
//
// El motor de Piixi no conoce aseguradoras. La ficha de una póliza sólo sabe
// preguntar «¿algún módulo INSTALADO declara relaciones para esta póliza?» y,
// si la respuesta es sí, pintar lo que ese módulo declaró — etiqueta, texto de
// «por qué», y qué tan la captura (por ahora sólo 'pdf'). Ninguna palabra de
// negocio de aseguradora vive en screen-policies.jsx: toda sale de
// RELACIONES_MODULOS, aquí abajo.
//
// Módulo de ejemplo: «Aviso de renovación de prestación» (GNP), que en pólizas
// de Conexión declara una relación de tipo 'prestacion' — la póliza que GNP
// exige tener vigente para que la de Conexión no caiga. Instalado por default,
// desinstalable desde su propio modal (ModuloDetalleModal); al desinstalarse,
// la palanca desaparece de TODAS las fichas — no queda rastro.

const { useState, useEffect, useRef } = React;

// ─────────────────────────────────────────────────────────────
// DECLARACIÓN DE MÓDULOS — toda la palabra de negocio vive aquí
// ─────────────────────────────────────────────────────────────
const RELACIONES_MODULOS = {
  conexion_aviso_renovacion: {
    id: 'conexion_aviso_renovacion',
    emisor: 'gnp',
    emisorNombre: 'GNP',
    titulo: 'Aviso de renovación de prestación',
    appliesTo: {
      carrier: 'gnp',
      productos: ['CONEXION GNP', 'Conexión Personaliza', 'PREMIER CONEXION'],
    },
    declaracion: {
      relaciones: [
        {
          tipo: 'prestacion',
          etiqueta: 'Póliza de prestación',
          porQue: 'Con ella Piixi te avisa antes de que venza y cruza suma y deducible',
          captura: 'pdf',
        },
      ],
    },
  },
};

// ─────────────────────────────────────────────────────────────
// STORE — módulos instalados + relaciones ligadas.
// Objetos mutables a nivel de módulo + un pub-sub minúsculo para que la
// ficha (drawer) y la píldora del encabezado (pill), que viven en
// componentes hermanos, se enteren del mismo cambio sin prop-drilling.
// ─────────────────────────────────────────────────────────────
let _modInstalado = { conexion_aviso_renovacion: true };
let _relLigadas = {}; // 'policyId::tipo' -> polizaId ligada (o ausente)

const _subs = new Set();
function _bump() { _subs.forEach((fn) => fn()); }

function useRelacionesLive() {
  const [, force] = useState(0);
  useEffect(() => {
    const fn = () => force((v) => v + 1);
    _subs.add(fn);
    return () => _subs.delete(fn);
  }, []);
}

function moduloInstalado(id) { return !!_modInstalado[id]; }
function setModuloInstalado(id, val) {
  _modInstalado = Object.assign({}, _modInstalado, { [id]: val });
  _bump();
}

function _relKey(policyId, tipo) { return policyId + '::' + tipo; }
function relLigadaA(policyId, tipo) { return _relLigadas[_relKey(policyId, tipo)] || null; }
function ligarRelacion(policyId, tipo, targetPolicyId) {
  _relLigadas = Object.assign({}, _relLigadas, { [_relKey(policyId, tipo)]: targetPolicyId });
  _bump();
}

// Qué relaciones declara el catálogo de módulos INSTALADOS para esta póliza.
// Ésta es la única puerta que la ficha usa — nunca lee RELACIONES_MODULOS
// directo, para que instalar/desinstalar sea la única palanca que importa.
function relacionesDeclaradasPara(p) {
  if (!p) return [];
  const out = [];
  Object.keys(RELACIONES_MODULOS).forEach((k) => {
    const mod = RELACIONES_MODULOS[k];
    if (!moduloInstalado(mod.id)) return;
    if (mod.appliesTo.carrier !== p.carrier) return;
    if (mod.appliesTo.productos.indexOf(p.producto) < 0) return;
    mod.declaracion.relaciones.forEach((rel) => out.push(Object.assign({ modulo: mod }, rel)));
  });
  return out;
}

// ─────────────────────────────────────────────────────────────
// DATOS FICTICIOS DE DEMOSTRACIÓN — se cargan UNA vez, antes de que el
// store (store.jsx) tome su snapshot de AdmixData.POLICIES. Dos pólizas de
// Conexión GNP GMM: (a) sin ligar, (b) ya ligada a su propia prestación
// (que también existe como póliza real, para poder abrir su ficha).
// ─────────────────────────────────────────────────────────────
(function seedRelacionesDemo() {
  if (window.__piixiRelSeed) return;
  window.__piixiRelSeed = true;

  const D = window.AdmixData;
  if (!D || !D.POLICIES) return;

  // El catálogo de productos GNP·GMM no traía los productos de Conexión.
  const gmmGnp = D.PRODUCTS && D.PRODUCTS.gnp && D.PRODUCTS.gnp.GMM;
  if (gmmGnp) {
    ['CONEXION GNP', 'Conexión Personaliza'].forEach((prod) => {
      if (gmmGnp.indexOf(prod) < 0) gmmGnp.push(prod);
    });
  }

  const c1 = 'c0001';
  const c2 = 'c0002';

  const polPrestA = {
    id: 'p-prest-a001',
    polizaNumero: 'MET-550231',
    carrier: 'metlife',
    ramo: 'GMM',
    producto: 'Met Salud',
    contratante: c1,
    status: 'AUTO_APPROVED',
    inicioVigencia: '2026-01-15',
    finVigencia: '2027-01-15',
    primaTotal: 19500,
    moneda: 'MXN',
    formaPago: 'Anual',
    diaPago: 15,
    createdAt: '2026-01-18',
    sourcePdf: 'met_salud_550231.pdf',
    asegurados: 1,
    provenance: 'fingerprint+udee',
  };

  const polCnxA = {
    id: 'p-cnx-a001',
    polizaNumero: 'GNP-CNX-100234',
    carrier: 'gnp',
    ramo: 'GMM',
    producto: 'CONEXION GNP',
    contratante: c1,
    status: 'AUTO_APPROVED',
    inicioVigencia: '2026-02-01',
    finVigencia: '2027-02-01',
    primaTotal: 24800,
    moneda: 'MXN',
    formaPago: 'Anual',
    diaPago: 1,
    createdAt: '2026-02-03',
    sourcePdf: 'gnp_conexion_gnp_100234.pdf',
    asegurados: 1,
    provenance: 'fingerprint+udee',
  };

  const polPrestB = {
    id: 'p-prest-b001',
    polizaNumero: 'AXA-330871',
    carrier: 'axa',
    ramo: 'GMM',
    producto: 'Plenitud',
    contratante: c2,
    status: 'AUTO_APPROVED',
    inicioVigencia: '2026-03-01',
    finVigencia: '2027-03-01',
    primaTotal: 27600,
    moneda: 'MXN',
    formaPago: 'Anual',
    diaPago: 1,
    createdAt: '2026-03-04',
    sourcePdf: 'axa_plenitud_330871.pdf',
    asegurados: 1,
    provenance: 'fingerprint+udee',
  };

  const polCnxB = {
    id: 'p-cnx-b001',
    polizaNumero: 'GNP-CNX-100897',
    carrier: 'gnp',
    ramo: 'GMM',
    producto: 'Conexión Personaliza',
    contratante: c2,
    status: 'AUTO_APPROVED',
    inicioVigencia: '2026-03-10',
    finVigencia: '2027-03-10',
    primaTotal: 31200,
    moneda: 'MXN',
    formaPago: 'Anual',
    diaPago: 10,
    createdAt: '2026-03-12',
    sourcePdf: 'gnp_conexion_personaliza_100897.pdf',
    asegurados: 1,
    provenance: 'fingerprint+udee',
  };

  D.POLICIES.push(polPrestA, polCnxA, polPrestB, polCnxB);

  // Contratante + asegurado titular, para que las barras de la ficha no
  // enseñen "sin identificar" en una póliza que sólo existe para la demo.
  if (window.AdmixPersonas && Array.isArray(window.AdmixPersonas.PARTIES)) {
    const PARTIES = window.AdmixPersonas.PARTIES;
    [[polCnxA, c1], [polPrestA, c1], [polCnxB, c2], [polPrestB, c2]].forEach(function (pair) {
      const pol = pair[0], cid = pair[1];
      PARTIES.push({ policyId: pol.id, personaId: cid, rol: 'CONTRATANTE', obligadoPago: true });
      PARTIES.push({ policyId: pol.id, personaId: cid, rol: 'ASEGURADO', obligadoPago: false, titular: true });
    });
  }

  // (b) nace ya ligada a su prestación; (a) nace sin ligar.
  ligarRelacion(polCnxB.id, 'prestacion', polPrestB.id);

  // A qué póliza "reconoce" el PDF simulado cuando el agente sube uno.
  window.__piixiRelTargets = {};
  window.__piixiRelTargets[polCnxA.id] = polPrestA.id;
  window.__piixiRelTargets[polCnxB.id] = polPrestB.id;
})();

// ─────────────────────────────────────────────────────────────
// UI — un renglón por relación declarada, con sus cuatro estados.
// ─────────────────────────────────────────────────────────────
function RelacionRow({ p, rel, linkedId, onAbrirModulo }) {
  const { navigate } = useHashRoute();
  const [transitorio, setTransitorio] = useState(null); // null | 'leyendo' | 'noreconocida'
  const intentos = useRef(0);

  const estado = transitorio === 'leyendo' ? 'leyendo'
    : transitorio === 'noreconocida' ? 'noreconocida'
    : linkedId ? 'ligada' : 'sinligar';

  function iniciarSubida() {
    setTransitorio('leyendo');
    setTimeout(function () {
      const primerIntento = intentos.current === 0;
      intentos.current += 1;
      if (primerIntento) {
        setTransitorio('noreconocida');
      } else {
        const target = (window.__piixiRelTargets && window.__piixiRelTargets[p.id]) || linkedId || null;
        setTransitorio(null);
        if (target) ligarRelacion(p.id, rel.tipo, target);
      }
    }, 1500);
  }

  const chip = (
    <button
      onClick={onAbrirModulo}
      style={{
        appearance: 'none', cursor: 'default', textAlign: 'left',
        background: 'var(--ax-bg-3)', border: '1px solid var(--ax-border)',
        borderRadius: 12, padding: '3px 10px', fontSize: 10.5, color: 'var(--ax-fg-muted)',
      }}
      onMouseEnter={(e) => e.currentTarget.style.background = 'var(--ax-bg-4)'}
      onMouseLeave={(e) => e.currentTarget.style.background = 'var(--ax-bg-3)'}
    >
      lo agrega: {rel.modulo.titulo} · {rel.modulo.emisorNombre}
    </button>
  );

  return (
    <div style={{ border: '1px solid var(--ax-border)', borderRadius: 8, padding: 14 }}>
      <div style={{ fontSize: 13, fontWeight: 500, color: 'var(--ax-fg-strong)' }}>{rel.etiqueta}</div>

      {estado === 'sinligar' ? (
        <>
          <div style={{ fontSize: 12, color: 'var(--ax-fg-muted)', marginTop: 4 }}>{rel.porQue}</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 10, flexWrap: 'wrap' }}>
            <AxButton variant="primary" icon="upload" onClick={iniciarSubida}>Subir su PDF</AxButton>
            {chip}
          </div>
        </>
      ) : null}

      {estado === 'leyendo' ? (
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 10, color: 'var(--ax-fg-muted)', fontSize: 12.5 }}>
          <span className="ax-spinner"/> Leyendo el PDF…
        </div>
      ) : null}

      {estado === 'noreconocida' ? (
        <>
          <div style={{ display: 'flex', gap: 8, alignItems: 'flex-start', marginTop: 8, color: 'var(--ax-danger)' }}>
            <AxIcon name="alert" size={14} style={{ flexShrink: 0, marginTop: 1 }}/>
            <div style={{ fontSize: 12.5 }}>No reconocimos esta póliza. Revisa que sea el PDF correcto</div>
          </div>
          <div style={{ marginTop: 10 }}>
            <AxButton variant="secondary" onClick={iniciarSubida}>Intentar con otro PDF</AxButton>
          </div>
        </>
      ) : null}

      {estado === 'ligada' ? (() => {
        const rp = AdmixData.policyById(linkedId);
        const rc = rp ? AdmixData.carrierById(rp.carrier) : null;
        return (
          <>
            <button
              onClick={() => navigate('/polizas/' + linkedId)}
              style={{
                appearance: 'none', cursor: 'default', textAlign: 'left', color: 'inherit',
                width: '100%', background: 'transparent', border: '1px solid var(--ax-border)',
                borderRadius: 6, padding: '10px 12px', marginTop: 10,
                display: 'flex', alignItems: 'center', gap: 10,
              }}
              onMouseEnter={(e) => e.currentTarget.style.background = 'var(--ax-bg-3)'}
              onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
            >
              <AxCarrierAvatar id={rp ? rp.carrier : null} size={20}/>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13, color: 'var(--ax-fg-strong)' }}>{rp ? rp.producto : 'Póliza no encontrada'}</div>
                <div className="ax-mono" style={{ fontSize: 11, color: 'var(--ax-fg-muted)' }}>
                  {rp ? rp.polizaNumero : '—'}{rc ? ' · ' + rc.name : ''}
                </div>
              </div>
              <div style={{ textAlign: 'right' }}>
                <div style={{ fontSize: 10, color: 'var(--ax-fg-faint)' }}>Vence</div>
                <div className="ax-mono" style={{ fontSize: 12, color: 'var(--ax-fg-strong)' }}>
                  {rp ? AdmixData.formatDateES(rp.finVigencia) : '—'}
                </div>
              </div>
              <AxIcon name="chevron-right" size={13} style={{ color: 'var(--ax-fg-faint)' }}/>
            </button>
            <div style={{ marginTop: 8 }}>
              <AxButton variant="tertiary" size="sm" onClick={iniciarSubida}>Cambiar</AxButton>
            </div>
          </>
        );
      })() : null}
    </div>
  );
}

// El «drawer»: tarjeta plegable con la misma piel que PolicyCardPlegable
// (screen-policies.jsx). Se replica el look aquí porque el orden de carga
// no permite importar ese componente todavía cuando este archivo corre.
function RelacionesDrawer({ p, abierta: abiertaProp, onToggle: onToggleProp }) {
  useRelacionesLive();
  const [abiertaLocal, setAbiertaLocal] = useState(false);
  const abierta = abiertaProp != null ? abiertaProp : abiertaLocal;
  const onToggle = onToggleProp || (() => setAbiertaLocal((v) => !v));
  const [moduloAbierto, setModuloAbierto] = useState(null);

  const relaciones = relacionesDeclaradasPara(p);
  if (!p || relaciones.length === 0) return null;

  const estados = relaciones.map((rel) => ({ rel, linkedId: relLigadaA(p.id, rel.tipo) }));
  const nSinLigar = estados.filter((e) => !e.linkedId).length;
  const resumen = nSinLigar > 0
    ? nSinLigar + (nSinLigar === 1 ? ' por ligar' : ' por ligar')
    : (estados.length === 1 ? '1 ligada' : estados.length + ' ligadas');

  return (
    <div className="ax-card" style={{ padding: 0, overflow: 'hidden' }}>
      <button
        onClick={onToggle}
        style={{
          appearance: 'none', background: 'transparent', border: 0, color: 'inherit',
          width: '100%', textAlign: 'left', cursor: 'default',
          padding: '13px 16px', display: 'flex', alignItems: 'center', gap: 10,
        }}
        onMouseEnter={(e) => e.currentTarget.style.background = 'var(--ax-bg-3)'}
        onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
      >
        <div style={{ flex: 1, minWidth: 0 }}>
          <h3 style={{ margin: 0, fontSize: 14, fontWeight: 500, color: 'var(--ax-fg-strong)' }}>Pólizas relacionadas</h3>
          <div style={{ fontSize: 11.5, color: 'var(--ax-fg-faint)', marginTop: 2 }}>{resumen}</div>
        </div>
        <AxIcon name={abierta ? 'chevron-down' : 'chevron-right'} size={13} style={{ color: 'var(--ax-fg-faint)' }}/>
      </button>
      {abierta ? (
        <div style={{ padding: '0 16px 16px', display: 'flex', flexDirection: 'column', gap: 10 }}>
          {estados.map(({ rel, linkedId }) => (
            <RelacionRow
              key={rel.tipo}
              p={p}
              rel={rel}
              linkedId={linkedId}
              onAbrirModulo={() => setModuloAbierto(rel.modulo.id)}
            />
          ))}
        </div>
      ) : null}
      <ModuloDetalleModal moduleId={moduloAbierto} onClose={() => setModuloAbierto(null)}/>
    </div>
  );
}

// Píldora discreta para el encabezado: sólo aparece si hay algo por ligar.
function FaltaLigarPill({ p, onOpen }) {
  useRelacionesLive();
  if (!p) return null;
  const relaciones = relacionesDeclaradasPara(p);
  const sinLigar = relaciones.find((rel) => !relLigadaA(p.id, rel.tipo));
  if (!sinLigar) return null;
  return (
    <button
      onClick={onOpen}
      style={{
        appearance: 'none', cursor: 'default',
        border: '1px dashed var(--ax-warm-line)', background: 'var(--ax-warm-soft)', color: 'var(--ax-warm)',
        borderRadius: 12, padding: '2px 10px', fontSize: 11.5,
        display: 'inline-flex', alignItems: 'center', gap: 6,
      }}
    >
      <AxIcon name="alert" size={11}/> Falta ligar: {sinLigar.etiqueta}
    </button>
  );
}

// Detalle del módulo: qué agrega, quién lo emite, instalar/desinstalar.
function ModuloDetalleModal({ moduleId, onClose }) {
  const { pushToast } = useAxStore();
  const mod = moduleId ? RELACIONES_MODULOS[moduleId] : null;
  if (!mod) return null;
  const instalado = moduloInstalado(mod.id);
  const rel = mod.declaracion.relaciones[0];

  return (
    <AxModal
      open={true}
      onClose={onClose}
      title={mod.titulo}
      width={460}
      footer={
        <AxButton
          variant={instalado ? 'secondary' : 'primary'}
          onClick={() => {
            setModuloInstalado(mod.id, !instalado);
            pushToast({
              kind: instalado ? 'info' : 'success',
              message: instalado ? 'Módulo desinstalado.' : 'Módulo instalado.',
            });
            onClose();
          }}
        >
          {instalado ? 'Desinstalar' : 'Instalar'}
        </AxButton>
      }
    >
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <AxCarrierAvatar id={mod.emisor} size={24}/>
          <div>
            <div style={{ fontSize: 13, color: 'var(--ax-fg-strong)' }}>{mod.emisorNombre}</div>
            <div style={{ fontSize: 11, color: 'var(--ax-fg-faint)' }}>Emisor del módulo</div>
          </div>
        </div>
        <div>
          <AxEyebrow style={{ marginBottom: 6 }}>Qué agrega a la ficha</AxEyebrow>
          <div style={{ fontSize: 12.5, color: 'var(--ax-fg-muted)' }}>
            En pólizas de Conexión ({mod.appliesTo.productos.join(', ')}) agrega: Ligar {rel.etiqueta} (por PDF).
          </div>
        </div>
        <div style={{ fontSize: 11.5, color: 'var(--ax-fg-faint)', borderTop: '1px solid var(--ax-border)', paddingTop: 10 }}>
          Si desinstalas el módulo, esta acción desaparece de las fichas.
        </div>
      </div>
    </AxModal>
  );
}

// Aviso de reinstalación — «ninguna superficie sin ruta»: desinstalar el
// módulo desde ModuloDetalleModal quita la palanca de TODAS las fichas, así
// que necesita su propia puerta de vuelta. Vive en la lista de Pólizas (no en
// la ficha, que es justo lo que dejó de tener la acción) y sólo se pinta
// mientras algún módulo declarado siga desinstalado. Toda la palabra de
// negocio (título del módulo, emisor) sale de RELACIONES_MODULOS — la lista
// de pólizas sólo la reenvía.
function ModulosDesinstaladosAviso() {
  useRelacionesLive();
  const { pushToast } = useAxStore();

  const desinstalados = Object.keys(RELACIONES_MODULOS)
    .map((k) => RELACIONES_MODULOS[k])
    .filter((mod) => !moduloInstalado(mod.id));
  if (desinstalados.length === 0) return null;

  return (
    <div style={{
      display: 'flex', flexDirection: 'column', gap: 4,
      padding: '8px 32px', background: 'var(--ax-warm-soft)',
      borderBottom: '1px solid var(--ax-border)',
    }}>
      {desinstalados.map((mod) => (
        <div key={mod.id} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12, color: 'var(--ax-fg-muted)' }}>
          <AxIcon name="info" size={12} style={{ color: 'var(--ax-warm)', flexShrink: 0 }}/>
          <span>
            Desinstalaste «{mod.titulo}» ({mod.emisorNombre}) ·{' '}
            <button
              onClick={() => {
                setModuloInstalado(mod.id, true);
                pushToast({ kind: 'success', message: 'Módulo instalado.' });
              }}
              style={{
                appearance: 'none', cursor: 'default', background: 'transparent', border: 0, padding: 0,
                color: 'var(--ax-accent)', textDecoration: 'underline', font: 'inherit',
              }}
            >
              Volver a instalar
            </button>
          </span>
        </div>
      ))}
    </div>
  );
}

Object.assign(window, {
  RelacionesDrawer, FaltaLigarPill, ModuloDetalleModal, ModulosDesinstaladosAviso,
  relacionesDeclaradasPara, moduloInstalado, setModuloInstalado,
  relLigadaA, ligarRelacion, RELACIONES_MODULOS,
});
