/* global React, ZoneBackdrop */
/**
 * Combat V2 — Pantalla de árbol de habilidad (5 nodos + compra con XP).
 *
 * Costes acumulados: suma de `cost_xp` de cada entrada en `treeTemplate.nodes`
 * (coincide con skill_trees.v2.json y con NODE_COSTS_CUMULATIVE del worker).
 *
 * El botón "Comprar" comprueba `xpEarned >= coste_acumulado` del siguiente nodo
 * (umbral real de desbloqueo). El texto del botón muestra el coste incremental
 * del nodo (`cost_xp` de esa entrada).
 */

const { useState, useMemo, useCallback, useEffect } = React;

/** Alineado con skill_xp.NODE_COSTS_CUMULATIVE — usado solo si falta `treeTemplate`. */
const FALLBACK_CUMULATIVE = [100, 350, 850, 1850, 3850];

const CATEGORY_ACCENT = {
  of: 'var(--color-of, #c0392b)',
  df: 'var(--color-df, #2980b9)',
  si: 'var(--color-si, #27ae60)',
};

function safeStr(v, fb = '') {
  if (v == null) return fb;
  return typeof v === 'string' ? v : String(v);
}

function humanizeId(id) {
  if (!id || typeof id !== 'string') return 'Habilidad';
  const tail = id.includes('_') ? id.slice(id.indexOf('_') + 1) : id;
  return tail.replace(/_/g, ' ');
}

function toPurchasedSet(purchased) {
  if (purchased instanceof Set) return new Set(purchased);
  if (Array.isArray(purchased)) return new Set(purchased);
  return new Set();
}

/**
 * @param {object | null | undefined} effect — TreeNodeEffect
 */
function formatEffect(effect) {
  if (!effect || typeof effect !== 'object') return '—';
  const k = effect.kind;
  switch (k) {
    case 'flat_damage_pct':
      return `+${effect.value}% daño base`;
    case 'flat_cd_pct':
      return `${effect.value}% tiempo de recarga`;
    case 'flat_duration_pct':
      return `+${effect.value}% duración`;
    case 'flat_crit_pct':
      return `+${effect.value}% prob. crítico`;
    case 'flat_mitigation_pct':
      return `+${effect.value}% mitigación`;
    case 'flat_absorb_pct':
      return `+${effect.value}% absorción`;
    case 'extra_target':
      return `+${effect.n} objetivo${effect.n > 1 ? 's' : ''}`;
    case 'wider_radius_pct':
      return `+${effect.value}% radio de área`;
    case 'spread_to_nearest_ally':
      return `Extiende ${effect.pct}% del efecto al aliado más cercano`;
    case 'auto_remove_debuff':
      return `Elimina ${effect.count} efecto${effect.count > 1 ? 's' : ''} negativo${effect.count > 1 ? 's' : ''} al activar`;
    case 'condition_satisfied_chance':
      return `${effect.pct}% de prob. de activar la condición automáticamente`;
    case 'final_ticks_double':
      return 'Los últimos ticks del daño continuo se duplican';
    case 'extra_collateral': {
      const w = effect.what === 'damage' ? 'daño' : effect.what === 'heal' ? 'curación' : 'efecto';
      return `+${effect.value} de ${w} colateral`;
    }
    case 'unknown':
    case 'placeholder':
      return '—';
    default:
      return JSON.stringify(effect);
  }
}

function buildPlaceholderNodes() {
  return [1, 2, 3, 4, 5].map((i) => {
    const incr = i === 1 ? 100 : i === 2 ? 250 : i === 3 ? 500 : i === 4 ? 1000 : 2000;
    return {
      index: i,
      name: `Nodo ${i}`,
      cost_xp: incr,
      effect: { kind: 'placeholder' },
    };
  });
}

/** Enriquece nodos con _cumulative y _incremental (números). */
function normalizeNodes(treeTemplate) {
  const raw = treeTemplate && Array.isArray(treeTemplate.nodes) ? treeTemplate.nodes : null;
  const list = !raw || raw.length === 0 ? buildPlaceholderNodes() : raw.slice(0, 5);
  let run = 0;
  const out = [];
  for (let i = 0; i < 5; i++) {
    const n = list[i] || {
      index: i + 1,
      name: `Nodo ${i + 1}`,
      cost_xp: FALLBACK_CUMULATIVE[i] - (i > 0 ? FALLBACK_CUMULATIVE[i - 1] : 0),
      effect: { kind: 'placeholder' },
    };
    const incr = typeof n.cost_xp === 'number' && n.cost_xp > 0
      ? n.cost_xp
      : (FALLBACK_CUMULATIVE[i] - (i > 0 ? FALLBACK_CUMULATIVE[i - 1] : 0));
    run += incr;
    out.push({
      ...n,
      index: typeof n.index === 'number' ? n.index : i + 1,
      name: safeStr(n.name, `Nodo ${i + 1}`),
      cost_xp: incr,
      effect: n.effect && typeof n.effect === 'object' ? n.effect : { kind: 'placeholder' },
      _incremental: incr,
      _cumulative: run,
    });
  }
  return out;
}

/** Primer nodo 1..5 no comprado tal que todos los anteriores están comprados. */
function getNextBuyIndex(purchased) {
  const s = toPurchasedSet(purchased);
  for (let i = 1; i <= 5; i++) {
    if (s.has(i)) continue;
    let ok = true;
    for (let j = 1; j < i; j++) {
      if (!s.has(j)) { ok = false; break; }
    }
    if (ok) return i;
  }
  return null;
}

function isMasterNode(node) {
  return (node && node.index === 5) || /maestría/i.test(safeStr(node && node.name, ''));
}

function SkillTreeScreen({
  ability,
  treeTemplate,
  xpEarned,
  purchasedNodes,
  onBuyNode,
  onBack,
}) {
  const ab = ability && typeof ability === 'object' ? ability : {};
  const abilityId = safeStr(ab.id, 'ability');
  const category = ab.category === 'df' || ab.category === 'si' ? ab.category : 'of';
  const secAccent = CATEGORY_ACCENT[category] || CATEGORY_ACCENT.of;

  const nodes = useMemo(() => normalizeNodes(treeTemplate), [treeTemplate]);

  const purchased = useMemo(() => toPurchasedSet(purchasedNodes), [purchasedNodes]);

  const nextBuyIndex = useMemo(() => getNextBuyIndex(purchased), [purchased]);

  const allMastered = useMemo(() => {
    for (let i = 1; i <= 5; i++) {
      if (!purchased.has(i)) return false;
    }
    return true;
  }, [purchased]);

  const [selectedNode, setSelectedNode] = useState(null);

  useEffect(() => {
    if (allMastered) {
      setSelectedNode(5);
      return;
    }
    if (nextBuyIndex != null) {
      setSelectedNode(nextBuyIndex);
      return;
    }
    setSelectedNode(1);
  }, [abilityId, nextBuyIndex, allMastered]);

  const selected = useMemo(
    () => nodes.find((n) => n.index === selectedNode) || nodes[0],
    [nodes, selectedNode],
  );

  const progressToNext = useMemo(() => {
    if (allMastered) return { pct: 1, label: 'Maestría alcanzada ★', ratio: 1 };
    if (nextBuyIndex == null) return { pct: 0, label: '', ratio: 0 };
    const n = nodes.find((x) => x.index === nextBuyIndex);
    const target = n ? n._cumulative : 1;
    const xp = typeof xpEarned === 'number' && xpEarned >= 0 ? xpEarned : 0;
    const ratio = Math.min(1, xp / target);
    return {
      pct: ratio * 100,
      ratio,
      label: `${Math.floor(xp)} / ${target} XP`,
    };
  }, [nodes, nextBuyIndex, xpEarned, allMastered]);

  const canBuyNext = useMemo(() => {
    if (nextBuyIndex == null) return false;
    const n = nodes.find((x) => x.index === nextBuyIndex);
    if (!n) return false;
    const xp = typeof xpEarned === 'number' ? xpEarned : 0;
    return xp >= n._cumulative;
  }, [nodes, nextBuyIndex, xpEarned]);

  const handleBuy = useCallback(() => {
    if (!canBuyNext || nextBuyIndex == null) return;
    if (typeof onBuyNode !== 'function') return;
    onBuyNode(abilityId, nextBuyIndex);
  }, [canBuyNext, nextBuyIndex, onBuyNode, abilityId]);

  const lineGradient = useMemo(() => {
    const parts = [];
    for (let i = 0; i < 5; i++) {
      const idx = i + 1;
      const p = purchased.has(idx);
      const t0 = (i / 5) * 100;
      const t1 = ((i + 1) / 5) * 100;
      const col = p ? 'var(--accent, #c8a860)' : 'rgba(255,255,255,0.12)';
      parts.push(`${col} ${t0}%`, `${col} ${t1}%`);
    }
    return `linear-gradient(90deg, ${parts.join(', ')})`;
  }, [purchased]);

  const zone = useMemo(() => ({
    id: 'skilltree',
    name: safeStr(ab.id, 'Árbol').replace(/_/g, ' '),
    tier: safeStr(ab.class, ''),
    bg: 'linear-gradient(180deg, #0b0d14 0%, #121826 50%, #0a0c12 100%)',
    silhouette: 'm 0 72 l 100 60 L 100 100 L 0 100 Z',
    horizon: 62,
    mood: 'arcane',
  }), [ab]);

  const ZB = typeof ZoneBackdrop === 'function' ? ZoneBackdrop : null;

  return (
    <div
      className="skilltree-screen"
      data-screen-label="Skill tree V2"
      style={{
        position: 'absolute',
        inset: 0,
        color: 'var(--ink-0, #efe9d7)',
        '--color-of': '#c0392b',
        '--color-df': '#2980b9',
        '--color-si': '#27ae60',
      }}
    >
      <style>{`
        @keyframes st-pulse {
          0%, 100% { box-shadow: 0 0 0 0 rgba(200, 168, 96, 0.35); }
          50% { box-shadow: 0 0 12px 2px rgba(200, 168, 96, 0.45); }
        }
        .skilltree-screen .st-node {
          width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
          font-size: 14px; font-weight: 700; cursor: pointer; z-index: 2; transition: transform 0.15s, opacity 0.15s;
        }
        .skilltree-screen .st-node:hover { transform: scale(1.06); }
        .skilltree-screen .st-node.purchased {
          background: var(--accent, #c8a860); color: #0a0c12; border: 2px solid var(--accent-soft, #a08840);
        }
        .skilltree-screen .st-node.next-ready {
          border: 2px solid var(--accent, #c8a860); background: rgba(200,168,96,0.12); color: var(--ink-0);
          animation: st-pulse 2s ease-in-out infinite;
        }
        .skilltree-screen .st-node.next-locked {
          border: 2px solid var(--accent, #c8a860); background: transparent; color: var(--ink-1);
        }
        .skilltree-screen .st-node.locked {
          background: rgba(255,255,255,0.05); opacity: 0.5; border: 1px solid rgba(255,255,255,0.12); color: var(--ink-3);
        }
        .skilltree-screen .st-node.master-purchased {
          border: 2px solid #d4af37; box-shadow: 0 0 8px rgba(212, 175, 55, 0.35);
        }
      `}</style>

      {ZB ? <ZB zone={zone} /> : null}

      <div style={{ position: 'relative', zIndex: 4, padding: '20px 24px 12px', maxWidth: 720, margin: '0 auto' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12, flexWrap: 'wrap' }}>
          <div>
            <div style={{ fontSize: 11, letterSpacing: '0.18em', color: 'var(--ink-2)', textTransform: 'uppercase' }}>Árbol de habilidad</div>
            <h1 style={{ fontFamily: 'Cinzel, serif', fontSize: 24, margin: '6px 0 4px', color: 'var(--ink-0)' }}>
              {humanizeId(abilityId)}
            </h1>
            <div style={{ fontSize: 13, color: 'var(--ink-2)', maxWidth: 560, lineHeight: 1.45 }}>
              {safeStr(ab.description, '').slice(0, 200)}{safeStr(ab.description).length > 200 ? '…' : ''}
            </div>
            <div style={{ fontSize: 12, color: secAccent, fontWeight: 600, marginTop: 8 }}>{abilityId}</div>
          </div>
          {typeof onBack === 'function' ? (
            <button type="button" className="btn btn-ghost" onClick={onBack}>← Volver</button>
          ) : null}
        </div>

        {/* Barra XP global hacia el siguiente nodo */}
        <div style={{ marginTop: 20, marginBottom: 8 }}>
          <div style={{ height: 8, borderRadius: 999, background: 'rgba(0,0,0,0.35)', overflow: 'hidden', border: '1px solid rgba(255,255,255,0.08)' }}>
            <div style={{
              width: `${progressToNext.pct}%`,
              height: '100%',
              background: `linear-gradient(90deg, ${secAccent}, var(--accent, #c8a860))`,
              transition: 'width 0.2s ease',
            }} />
          </div>
          <div style={{ marginTop: 6, fontSize: 13, color: 'var(--ink-2)', textAlign: 'right' }}>
            {progressToNext.label}
          </div>
        </div>

        {/* 5 nodos + línea */}
        <div style={{ position: 'relative', marginTop: 28, padding: '0 8px' }}>
          <div
            style={{
              position: 'absolute',
              left: 24,
              right: 24,
              top: 22,
              height: 3,
              borderRadius: 2,
              background: lineGradient,
              zIndex: 0,
            }}
          />
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', position: 'relative', zIndex: 1 }}>
            {nodes.map((node) => {
              const idx = node.index;
              const isPurch = purchased.has(idx);
              const isNext = nextBuyIndex === idx;
              const isFuture = !isPurch && !isNext && (nextBuyIndex != null && idx > nextBuyIndex);
              const isPastLocked = !isPurch && nextBuyIndex != null && idx < nextBuyIndex;
              const master = isMasterNode(node);

              let cls = 'st-node locked';
              if (isPurch) {
                cls = master ? 'st-node purchased master-purchased' : 'st-node purchased';
              } else if (isNext) {
                cls = canBuyNext ? 'st-node next-ready' : 'st-node next-locked';
              } else if (isFuture || isPastLocked) {
                cls = 'st-node locked';
              }

              const showStar = master;
              const label = showStar ? '★' : String(idx);

              return (
                <div
                  key={idx}
                  role="button"
                  tabIndex={0}
                  className={cls}
                  onClick={() => setSelectedNode(idx)}
                  onMouseEnter={() => setSelectedNode(idx)}
                  onKeyDown={(e) => {
                    if (e.key === 'Enter' || e.key === ' ') {
                      e.preventDefault();
                      setSelectedNode(idx);
                    }
                  }}
                >
                  {isPurch ? '✓' : label}
                </div>
              );
            })}
          </div>
        </div>

        {/* Tarjeta nodo seleccionado */}
        <div style={{
          marginTop: 28,
          padding: 18,
          borderRadius: 12,
          background: 'var(--bg-2, #10141d)',
          border: `1px solid rgba(255,255,255,0.1)`,
          boxShadow: isMasterNode(selected) && purchased.has(5) ? '0 0 0 1px rgba(212,175,55,0.35)' : 'none',
        }}
        >
          <div style={{ fontSize: 12, color: secAccent, letterSpacing: '0.12em', textTransform: 'uppercase' }}>
            Nodo {selected && selected.index} {isMasterNode(selected) ? '· Maestría ★' : ''}
          </div>
          <h2 style={{ fontFamily: 'Cinzel, serif', fontSize: 20, margin: '8px 0 10px', color: 'var(--ink-0)' }}>
            {isMasterNode(selected) ? `★ ${safeStr(selected && selected.name, '')}` : safeStr(selected && selected.name, '—')}
          </h2>
          <p style={{ fontSize: 14, lineHeight: 1.5, color: 'var(--ink-1)', margin: 0 }}>
            {formatEffect(selected && selected.effect)}
          </p>
          <div style={{ marginTop: 14, display: 'flex', gap: 24, flexWrap: 'wrap', fontSize: 13, color: 'var(--ink-2)' }}>
            <div>
              <strong style={{ color: 'var(--ink-0)' }}>Coste acumulado</strong><br />
              {selected ? selected._cumulative : '—'} XP total hasta aquí
            </div>
            <div>
              <strong style={{ color: 'var(--ink-0)' }}>Coste incremental</strong><br />
              {selected ? selected._incremental : '—'} XP este nodo
            </div>
          </div>
        </div>

        {/* Comprar */}
        {!allMastered && nextBuyIndex != null && selected && selected.index === nextBuyIndex ? (
          <div style={{ marginTop: 20, textAlign: 'center' }}>
            <button
              type="button"
              className="btn btn-accent btn-xl"
              disabled={!canBuyNext}
              onClick={handleBuy}
              style={{ opacity: canBuyNext ? 1 : 0.45 }}
            >
              {(() => {
                const n = nodes.find((x) => x.index === nextBuyIndex);
                const name = n ? safeStr(n.name, 'Nodo') : 'Nodo';
                const incr = n ? n._incremental : 0;
                return `Comprar ${name} — ${incr} XP`;
              })()}
            </button>
            {!canBuyNext ? (
              <div style={{ marginTop: 8, fontSize: 12, color: 'var(--ink-3)' }}>
                Necesitas {(() => {
                  const n = nodes.find((x) => x.index === nextBuyIndex);
                  return n ? n._cumulative : 0;
                })()} XP acumulados en esta habilidad para desbloquear este nodo.
              </div>
            ) : null}
          </div>
        ) : null}

        {allMastered ? (
          <div style={{ marginTop: 24, textAlign: 'center', fontSize: 18, color: 'var(--accent)', fontFamily: 'Cinzel, serif' }}>
            Maestría alcanzada ★
          </div>
        ) : null}
      </div>
    </div>
  );
}

Object.assign(window, {
  SkillTreeScreen,
  formatEffect,
});
