// Vista mapa estelar — sidebar de secciones + cúmulos radiales.
// Click en estrella para abrir poema. Click en sección para focalizar cúmulo.

const { useState: useStateC, useEffect: useEffectC, useRef: useRefC, useMemo: useMemoC } = React;

const GOLDEN_ANGLE = Math.PI * (3 - Math.sqrt(5));

function hashStr(s) {
  let h = 0;
  for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0;
  return Math.abs(h);
}

function clusterCenters(n, W, H) {
  const cx = W / 2, cy = H / 2;
  if (n === 1) return [[cx, cy]];
  if (n === 2) return [[W * 0.3, cy], [W * 0.7, cy]];
  if (n === 3) return [[W * 0.3, H * 0.36], [W * 0.7, H * 0.36], [W * 0.5, H * 0.74]];
  if (n === 4) return [[W * 0.28, H * 0.32], [W * 0.72, H * 0.32], [W * 0.28, H * 0.74], [W * 0.72, H * 0.74]];
  const R = Math.min(W, H) * 0.32;
  return Array.from({ length: n }, (_, i) => {
    const a = (i / n) * Math.PI * 2 - Math.PI / 2;
    return [cx + Math.cos(a) * R, cy + Math.sin(a) * R];
  });
}

function Constellation({ onOpen, leidos = {} }) {
  const wrapRef = useRefC(null);
  const [size, setSize] = useStateC({ w: 800, h: 600 });
  const [hover, setHover] = useStateC(null);
  const [selected, setSelected] = useStateC(null);
  const [hoverSection, setHoverSection] = useStateC(null);

  useEffectC(() => {
    const onResize = () => {
      if (!wrapRef.current) return;
      const r = wrapRef.current.getBoundingClientRect();
      setSize({ w: r.width, h: r.height });
    };
    onResize();
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  const sectionKeys = Object.keys(window.SECCIONES);
  const W = size.w, H = size.h;
  const baseR = Math.min(W, H) * 0.16;

  const layout = useMemoC(() => {
    const centers = clusterCenters(sectionKeys.length, W, H);

    return sectionKeys.map((secKey, secIdx) => {
      const poems = window.POEMS.filter(p => p.seccion === secKey)
                                .sort((a, b) => a.orden - b.orden);
      const [cx, cy] = centers[secIdx];
      const stars = poems.map((p, i) => {
        const seed = hashStr(p.slug);
        if (poems.length === 1) {
          return { poem: p, x: cx, y: cy, r: 4 };
        }
        const angle = i * GOLDEN_ANGLE + ((seed % 1000) / 1000) * 0.18;
        const t = (i + 1) / (poems.length + 1);
        const radius = baseR * (0.4 + 0.65 * Math.sqrt(t));
        return {
          poem: p,
          x: cx + Math.cos(angle) * radius,
          y: cy + Math.sin(angle) * radius,
          r: 3 + ((seed >> 4) % 2),
        };
      });
      const written = poems.filter(p => p.texto).length;
      const read = poems.filter(p => leidos[p.slug]).length;
      return {
        secKey, secIdx, cx, cy,
        stars,
        label: window.SECCIONES[secKey].nombre,
        total: poems.length,
        written,
        read,
      };
    });
  }, [W, H, sectionKeys.join(","), JSON.stringify(leidos)]);

  const dimFor = (key) => {
    if (selected && selected !== key) return 0.18;
    if (hoverSection && hoverSection !== key) return 0.4;
    return 1;
  };

  const hoveredStar = useMemoC(() => {
    if (!hover) return null;
    for (const row of layout) {
      const s = row.stars.find(x => x.poem.slug === hover);
      if (s) return { star: s, row };
    }
    return null;
  }, [hover, layout]);

  return (
    <div className="cnst">
      <aside className="cnst-aside">
        <div className="cnst-aside-title">SECCIONES</div>
        <ul className="cnst-aside-list">
          {layout.map(row => {
            const active = selected === row.secKey;
            const pendientes = row.total - row.written;
            return (
              <li
                key={row.secKey}
                className={`cnst-aside-item${active ? " active" : ""}`}
                onMouseEnter={() => setHoverSection(row.secKey)}
                onMouseLeave={() => setHoverSection(null)}
                onClick={() => setSelected(active ? null : row.secKey)}
              >
                <div className="cnst-aside-name">
                  <span className="cnst-aside-num">§ 0{row.secIdx + 1}</span>
                  <span>{row.label}</span>
                </div>
                <div className="cnst-aside-meta">
                  {row.read}/{row.written} leídos
                  {pendientes > 0 && ` · ${pendientes} pendiente${pendientes > 1 ? "s" : ""}`}
                </div>
              </li>
            );
          })}
        </ul>
        {selected && (
          <div className="cnst-aside-clear" onClick={() => setSelected(null)}>
            ← limpiar filtro
          </div>
        )}
      </aside>

      <div className="cnst-canvas" ref={wrapRef}>
        <svg className="cnst-svg" width={W} height={H}>
          {layout.map(row => {
            const op = dimFor(row.secKey);
            const writtenStars = row.stars.filter(s => s.poem.texto);
            let pathD = "";
            if (writtenStars.length >= 2) {
              pathD = `M ${writtenStars[0].x} ${writtenStars[0].y}`;
              for (let i = 1; i < writtenStars.length; i++) {
                pathD += ` L ${writtenStars[i].x} ${writtenStars[i].y}`;
              }
            }
            return (
              <g key={row.secKey} style={{ opacity: op, transition: "opacity .25s" }}>
                {pathD && (
                  <path
                    d={pathD}
                    stroke="var(--phosphor-dim)"
                    strokeWidth="1"
                    fill="none"
                    strokeDasharray="3 5"
                  />
                )}

                <text
                  x={row.cx}
                  y={row.cy - baseR - 16}
                  fill="var(--phosphor)"
                  fontSize="11"
                  fontFamily="var(--mono)"
                  letterSpacing="0.24em"
                  textAnchor="middle"
                  style={{ textTransform: "uppercase", pointerEvents: "none" }}
                >
                  § 0{row.secIdx + 1} · {row.label}
                </text>

                {row.stars.map(s => {
                  const written = !!s.poem.texto;
                  const read = !!leidos[s.poem.slug];
                  const isHover = hover === s.poem.slug;
                  return (
                    <g
                      key={s.poem.slug}
                      transform={`translate(${s.x}, ${s.y})`}
                      style={{ cursor: written ? "pointer" : "not-allowed" }}
                      onMouseEnter={() => setHover(s.poem.slug)}
                      onMouseLeave={() => setHover(null)}
                      onClick={() => written && onOpen(s.poem.slug)}
                    >
                      {written && (
                        <circle
                          r={s.r * (isHover ? 7 : 4.5)}
                          fill="var(--phosphor)"
                          opacity={isHover ? 0.24 : 0.12}
                        />
                      )}
                      <circle
                        r={s.r * (isHover ? 1.6 : 1)}
                        fill={written ? "var(--phosphor)" : "var(--phosphor-faint)"}
                        opacity={written ? 1 : 0.5}
                      />
                      {read && (
                        <circle
                          r={s.r + 5}
                          fill="none"
                          stroke="var(--phosphor)"
                          strokeWidth="1"
                          opacity="0.75"
                        />
                      )}
                    </g>
                  );
                })}
              </g>
            );
          })}
        </svg>

        {hoveredStar && (
          <div
            className="cnst-tooltip"
            style={{ left: hoveredStar.star.x, top: hoveredStar.star.y }}
          >
            <div className="cnst-tt-title">{hoveredStar.star.poem.titulo}</div>
            <div className="cnst-tt-meta">
              {hoveredStar.row.label}
              {hoveredStar.star.poem.tema ? ` · ${hoveredStar.star.poem.tema}` : ""}
            </div>
            <div className="cnst-tt-state">
              {hoveredStar.star.poem.texto
                ? (leidos[hoveredStar.star.poem.slug] ? "leído · click para reabrir" : "click para entrar")
                : "pendiente"}
            </div>
          </div>
        )}

        <div className="cnst-legend">
          <div className="cnst-legend-title">leyenda</div>
          <div className="cnst-legend-row"><span className="lg-dot full" /> escrito</div>
          <div className="cnst-legend-row"><span className="lg-dot ring" /> leído</div>
          <div className="cnst-legend-row"><span className="lg-dot dim" /> pendiente</div>
        </div>
      </div>
    </div>
  );
}

window.Constellation = Constellation;
