/* FINAZ — Cadena causa-efecto.
   Grafo dirigido de eventos macro: cada nodo es una variable que se mueve (↑/↓)
   y las aristas muestran la relación causal. Propagación animada por pasos
   (vía estado), hover que ilumina el impacto aguas abajo y narrativa sincronizada. */
(function () {
  "use strict";
  const { useState, useEffect, useRef, useMemo, useCallback } = React;
  const e = React.createElement;
  const UI = window.FinazUI;

  const W = 980, H = 470;
  const NW = 134, NH = 52;

  // ---------- definición del grafo ----------
  const NODES = {
    inflacion: { lines: ["Inflación", "(IPC)"], dir: "up", tone: "cause", x: 88, y: 235,
      gloss: { term: "Inflación (IPC)", text: "El ritmo al que suben los precios. Es la causa raíz de esta cadena: cuando se descontrola, el banco central reacciona." } },
    tipos: { lines: ["Tipos de", "interés"], dir: "up", tone: "effect", x: 290, y: 235,
      gloss: { term: "Tipos de interés", text: "El precio del dinero que fija el banco central. Subirlos enfría la economía y la inflación, pero encarece financiarse." } },
    consumo: { lines: ["Consumo", "de hogares"], dir: "down", tone: "effect", x: 492, y: 366,
      gloss: { term: "Consumo", text: "El gasto de las familias. Con tipos altos, las hipotecas y el crédito cuestan más, así que se gasta menos." } },
    crecimiento: { lines: ["Crecimiento", "económico"], dir: "down", tone: "down", x: 694, y: 366,
      gloss: { term: "Crecimiento (PIB)", text: "El ritmo de la actividad económica. Si el consumo y la inversión se frenan, el crecimiento se resiente." } },
    coste: { lines: ["Coste de", "financiación"], dir: "up", tone: "effect", x: 492, y: 104,
      gloss: { term: "Coste de financiación", text: "Lo que paga una empresa por endeudarse. Con tipos altos, financiar proyectos e inversiones es más caro." } },
    beneficios: { lines: ["Beneficios", "esperados"], dir: "down", tone: "down", x: 694, y: 104,
      gloss: { term: "Beneficios esperados", text: "La previsión de ganancias futuras de las empresas. Si financiarse cuesta más, esas previsiones bajan." } },
    bono: { lines: ["Rentabilidad", "del bono"], dir: "up", tone: "effect", x: 492, y: 235,
      gloss: { term: "Rentabilidad del bono", text: "El interés que paga la deuda pública. Sube con los tipos y ofrece retorno con menos riesgo que la bolsa." } },
    compite: { lines: ["Atractivo", "del bono"], dir: "up", tone: "effect", x: 694, y: 235,
      gloss: { term: "Bono vs. bolsa", text: "Cuando el bono renta más sin apenas riesgo, parte del dinero deja la renta variable y busca esa seguridad." } },
    bolsas: { lines: ["Bolsas", "(R. variable)"], dir: "down", tone: "down", x: 892, y: 170,
      gloss: { term: "Renta variable", text: "Las acciones cotizadas. Aquí reciben un doble golpe: menores beneficios esperados y la competencia del bono." } },
  };
  const EDGES = [
    ["inflacion", "tipos", "fuerza"],
    ["tipos", "consumo", "enfría"],
    ["consumo", "crecimiento", "frena"],
    ["tipos", "coste", "encarece"],
    ["coste", "beneficios", "reduce"],
    ["tipos", "bono", "eleva"],
    ["bono", "compite", "atrae"],
    ["beneficios", "bolsas", "presiona"],
    ["compite", "bolsas", "drena"],
  ];
  const ORDER = ["inflacion", "tipos", "consumo", "crecimiento", "coste", "beneficios", "bono", "compite", "bolsas"];
  const BODY = {
    inflacion: "Todo arranca aquí: los precios suben más rápido de lo deseable. El banco central no puede ignorarlo.",
    tipos: "Para frenar la inflación, el banco central sube los tipos de interés. Es su principal herramienta… y la que pone en marcha toda la cadena.",
    consumo: "Con el crédito más caro, las familias gastan menos. El consumo, motor de la economía, pierde fuelle.",
    crecimiento: "Menos consumo significa menos actividad: el crecimiento económico se desacelera.",
    coste: "En paralelo, a las empresas les cuesta más financiarse. Cada proyecto e inversión sale más caro.",
    beneficios: "Si financiarse cuesta más, los beneficios futuros esperados se recortan. El mercado lo descuenta de inmediato.",
    bono: "Al subir los tipos, la deuda pública paga más. El bono se vuelve una alternativa con retorno y poco riesgo.",
    compite: "Ese bono más rentable compite con la bolsa: parte del dinero migra buscando seguridad.",
    bolsas: "Resultado: con beneficios a la baja y el bono compitiendo, las bolsas ceden. Dos caminos, un mismo desenlace.",
  };

  // adyacencia y descendientes
  const ADJ = {}; EDGES.forEach(([a, b]) => { (ADJ[a] = ADJ[a] || []).push(b); });
  function descendants(id) { const out = new Set(); const stack = [...(ADJ[id] || [])]; while (stack.length) { const x = stack.pop(); if (!out.has(x)) { out.add(x); (ADJ[x] || []).forEach((y) => stack.push(y)); } } return out; }

  const CHAIN = {
    source: "Relaciones macro simplificadas con fines formativos. La realidad incluye matices y excepciones.",
    disclaimer: "FINAZ es una plataforma de formación e información. No ofrece asesoramiento de inversión, ni recomendaciones de compra/venta, ni predicciones accionables.",
  };
  window.FINAZ_CHAIN = { NODES, EDGES, ORDER, BODY, CHAIN };

  // ---------- diagrama ----------
  function ChainDiagram({ theme, activeId, revealed, showRel, onHover }) {
    const T = theme.tokens, C = theme.chart;
    const toneColor = (tone) => tone === "cause" ? T.accent2 : tone === "down" ? T.neg : T.accent;
    const glowId = "chglow-" + theme.id;
    const arrOn = "arrOn-" + theme.id, arrOff = "arrOff-" + theme.id;

    // geometría de aristas: de borde derecho del origen a borde izquierdo del destino
    function edgePath(a, b) {
      const A = NODES[a], B = NODES[b];
      const x1 = A.x + NW / 2, y1 = A.y, x2 = B.x - NW / 2, y2 = B.y;
      const dx = Math.max(40, (x2 - x1) * 0.5);
      return "M" + x1 + "," + y1 + " C" + (x1 + dx) + "," + y1 + " " + (x2 - dx) + "," + y2 + " " + x2 + "," + y2;
    }

    return e("svg", { width: "100%", viewBox: "0 0 " + W + " " + H, style: { display: "block" },
      onPointerLeave: () => onHover(null) },
      e("defs", null,
        e("filter", { id: glowId, x: "-40%", y: "-40%", width: "180%", height: "180%" },
          e("feGaussianBlur", { stdDeviation: C.glow ? 3 : 0, result: "b" }),
          e("feMerge", null, e("feMergeNode", { in: "b" }), e("feMergeNode", { in: "SourceGraphic" }))),
        [[arrOn, T.accent], [arrOff, T.faint]].map(([id, col]) =>
          e("marker", { key: id, id, viewBox: "0 0 10 10", refX: 8, refY: 5, markerWidth: 7, markerHeight: 7, orient: "auto-start-reverse" },
            e("path", { d: "M0,0 L10,5 L0,10 z", fill: col })))),

      // aristas
      EDGES.map(([a, b, rel], i) => {
        const on = revealed.has(a) && revealed.has(b);
        const d = edgePath(a, b);
        const mid = midPoint(NODES[a], NODES[b]);
        return e("g", { key: i },
          e("path", { d, fill: "none", stroke: on ? toneColor(NODES[b].tone) : T.faint, strokeWidth: on ? 2.2 : 1.2, opacity: on ? 0.95 : 0.4, markerEnd: "url(#" + (on ? arrOn : arrOff) + ")", filter: on && C.glow ? "url(#" + glowId + ")" : "none" }),
          (showRel && on) && e("g", null,
            e("rect", { x: mid.x - rel.length * 3.1 - 6, y: mid.y - 9, width: rel.length * 6.2 + 12, height: 18, rx: 9, fill: T.panel, stroke: T.panelEdge, strokeWidth: 1 }),
            e("text", { x: mid.x, y: mid.y + 3.5, textAnchor: "middle", fontFamily: theme.fonts.mono, fontSize: 9.5, fill: T.sub }, rel)));
      }),

      // nodos
      Object.keys(NODES).map((id) => {
        const N = NODES[id], on = revealed.has(id), active = id === activeId;
        const col = toneColor(N.tone);
        const x = N.x - NW / 2, y = N.y - NH / 2;
        return e("g", { key: id, style: { cursor: "pointer" },
          onPointerEnter: () => onHover(id), onClick: () => onHover(id) },
          e("rect", { x, y, width: NW, height: NH, rx: C.radius ? 13 : 3,
            fill: on ? "color-mix(in srgb, " + col + " 14%, " + T.panel + ")" : T.panel,
            stroke: active ? col : (on ? col : T.faint), strokeWidth: active ? 2.6 : (on ? 1.7 : 1),
            opacity: on ? 1 : 0.55, filter: active && C.glow ? "url(#" + glowId + ")" : "none" }),
          // texto
          N.lines.map((ln, k) => e("text", { key: k, x: N.x - 8, y: N.y + (N.lines.length === 2 ? (k === 0 ? -3 : 12) : 4),
            textAnchor: "middle", fontFamily: theme.fonts.display, fontWeight: 600, fontSize: 13.5,
            fill: on ? T.ink : T.sub }, ln)),
          // badge dirección
          e("g", { transform: "translate(" + (x + NW - 16) + "," + (y + 15) + ")" },
            e("circle", { r: 10, fill: on ? col : T.chip, opacity: on ? 1 : 0.6 }),
            e("text", { x: 0, y: 4, textAnchor: "middle", fontFamily: theme.fonts.body, fontWeight: 700, fontSize: 13, fill: on ? (theme.mode === "light" ? "#fff" : T.bg) : T.sub }, N.dir === "up" ? "↑" : "↓")));
      })
    );
  }
  function midPoint(A, B) { const x1 = A.x + NW / 2, x2 = B.x - NW / 2; return { x: (x1 + x2) / 2, y: (A.y + B.y) / 2 }; }

  /* ───────────────── vista cadena ───────────────── */
  function FinazChainView({ theme }) {
    const [step, setStep] = useState(null);     // índice de propagación (null = inicio)
    const [playing, setPlaying] = useState(false);
    const [hoverId, setHoverId] = useState(null);
    const [layers, setLayers] = useState({ relaciones: true, fuentes: true });

    useEffect(() => { if (!window.__fzNarr) window.__fzNarr = {}; if (!window.__fzNarr.chain) { window.__fzNarr.chain = true; const t = setTimeout(() => setPlaying(true), 1200); return () => clearTimeout(t); } }, []);
    useEffect(() => { setStep(null); setPlaying(false); setHoverId(null); }, [theme.family]);
    useEffect(() => {
      if (!playing) return;
      const start = (step == null || step >= ORDER.length - 1) ? 0 : step;
      let s = start; setStep(s);
      const iv = setInterval(() => { s += 1; if (s >= ORDER.length) { clearInterval(iv); setPlaying(false); } else setStep(s); }, 2100);
      return () => clearInterval(iv);
    }, [playing]); // eslint-disable-line

    const togglePlay = () => { if (playing) setPlaying(false); else { if (step == null || step >= ORDER.length - 1) setStep(0); setPlaying(true); } };
    const onHover = useCallback((id) => { setHoverId(id); if (id) setPlaying(false); }, []);

    // estado derivado: activo + revelados
    let activeId = null; const revealed = new Set();
    if (hoverId) { activeId = hoverId; revealed.add(hoverId); descendants(hoverId).forEach((x) => revealed.add(x)); }
    else if (step != null) { activeId = ORDER[step]; for (let i = 0; i <= step; i++) revealed.add(ORDER[i]); }

    const node = activeId ? NODES[activeId] : null;
    const cards = node ? [{ type: "term", label: "Glosario", head: node.gloss.term, text: node.gloss.text }] : [];
    const tone = node ? node.tone : null;

    return e("div", { className: "fz-stage" },
      e("section", { className: "fz-left" },
        e("div", { className: "fz-symrow" },
          e("div", { className: "fz-sym" },
            e("div", { className: "fz-symname" }, e("strong", null, "Cadena causa-efecto"), e("span", null, "Cómo la inflación llega a las bolsas")),
          ),
          UI.e(UI.LayerChips, { layers, onToggle: (k) => setLayers((s) => ({ ...s, [k]: !s[k] })), defs: [["relaciones", "Relaciones"], ["fuentes", "Fuentes"]] })
        ),
        e("div", { className: "fz-chartcard fz-chaincard" },
          e(ChainDiagram, { theme, activeId, revealed, showRel: layers.relaciones, onHover }),
          e("div", { className: "fz-chainhint" }, "Pasa el cursor por un nodo para ver qué desencadena ·  ▶ para ver la propagación")
        ),
        e("div", { className: "fz-timeline" },
          ORDER.map((id, i) => e("div", { key: id, className: "fz-tlseg" + (activeId === id ? " on" : ""), style: { flex: 1 },
            onClick: () => { setPlaying(false); setHoverId(null); setStep(i); } },
            e("span", { className: "fz-tltag" }, NODES[id].lines.join(" ")))),
          (step != null && !hoverId) && e("div", { className: "fz-playhead", style: { left: (step / (ORDER.length - 1) * 100) + "%" } })
        ),
        e(UI.SourcesFooter, { on: layers.fuentes, source: CHAIN.source, disclaimer: CHAIN.disclaimer })
      ),
      e("aside", { className: "fz-right" },
        e(UI.PlayBar, { playing, idle: step == null && !hoverId, progress: (step == null) ? 0 : step / (ORDER.length - 1), onToggle: togglePlay, idleLabel: "Reproducir propagación" }),
        node
          ? e(UI.NarrativeCard, { anim: activeId, tag: node.dir === "up" ? "Sube ↑" : "Baja ↓", kind: tone === "down" ? "down" : (tone === "cause" ? "" : "up"), title: node.gloss.term, body: BODY[activeId] })
          : e(UI.NarrativeCard, { summary: true, tag: "Cadena causa-efecto", title: "Un evento nunca viaja solo",
              body: e(React.Fragment, null, "Cada pieza empuja a la siguiente. Pulsa ", e("strong", null, "Reproducir propagación"), " para seguir la historia de la inflación hasta las bolsas, o explora un nodo para ver su efecto dominó."),
              children: e(UI.StatGrid, { stats: [["Nodos", Object.keys(NODES).length], ["Relaciones", EDGES.length], ["Origen", "Inflación"], ["Desenlace", "Bolsas"]] }) }),
        e(UI.ExtraCards, { cards })
      )
    );
  }

  window.FinazChainView = FinazChainView;
})();
