/* global React, window */
/* ============================================================
   SKILLS CREATOR — Perícias do Escriba de Arton
   ============================================================
   - Lê window.CHAR_SKILLS (store) + window.CHAR_ATTRS + window.SKILLS
   - Layout no spread do livro: página esquerda = síntese,
     página direita = grid de perícias agrupado por atributo.
   - Cada perícia treinada mostra a fonte (class_fixed | class_choice |
     int_bonus | origin | power) via borda lateral colorida + selo abreviado.
   - Briefing original em: pasted_text (m0001). UI provisória.
   ============================================================ */

(function () {
  "use strict";
  const { useState, useEffect, useMemo, useCallback, useRef } = React;

  // -----------------------------------------------------------------------
  // Constantes
  // -----------------------------------------------------------------------
  const ATTRS = ["FOR", "DES", "CON", "INT", "SAB", "CAR"];
  const ATTR_LABELS = {
    FOR: "Força", DES: "Destreza", CON: "Constituição",
    INT: "Inteligência", SAB: "Sabedoria", CAR: "Carisma",
  };

  // Fontes da treinamento — chave do skills-store
  const SOURCE_META = {
    class_fixed:  { short: "FIX", label: "Fixa da classe",        tone: "class-fixed"  },
    class_choice: { short: "CL",  label: "Escolha de classe",     tone: "class-choice" },
    int_bonus:    { short: "INT", label: "Bônus de Inteligência", tone: "int" },
    race:         { short: "RAC", label: "Raça",                  tone: "race" },
    origin:       { short: "ORI", label: "Origem",                tone: "origin" },
    power:        { short: "POD", label: "Poder",                 tone: "power" },
  };
  const SOURCE_ORDER = ["class_fixed", "class_choice", "int_bonus", "race", "origin", "power"];

  // -----------------------------------------------------------------------
  // Helpers de regra T20
  // -----------------------------------------------------------------------
  function trainingBonus(level) {
    if (level >= 15) return 6;
    if (level >= 7)  return 4;
    return 2;
  }

  function calcBonus({ trained, level, attrMod }) {
    const half = Math.floor((level || 1) / 2);
    const tr = trained ? trainingBonus(level || 1) : 0;
    return { total: half + (attrMod || 0) + tr, half, train: tr, attr: attrMod || 0 };
  }

  function lsRead(key) {
    try { return JSON.parse(localStorage.getItem(key)); } catch { return null; }
  }

  /* O briefing diz "arton_class.level", mas o class-creator real salva em
     "arton_char_class" como { classes: [{className, level, …}, …] }.
     Tentamos as duas formas pra não quebrar. */
  function readCharLevel() {
    const a = lsRead("arton_char_class");
    if (a && Array.isArray(a.classes) && a.classes.length) {
      return a.classes.reduce((sum, c) => sum + (c.level || 1), 0);
    }
    const b = lsRead("arton_class");
    if (b && typeof b.level === "number") return b.level;
    return 1;
  }

  // -----------------------------------------------------------------------
  // Hooks
  // -----------------------------------------------------------------------
  function useSkillsState() {
    const [s, setS] = useState(() =>
      window.CHAR_SKILLS ? window.CHAR_SKILLS.getState() : null
    );
    useEffect(() => {
      if (!window.CHAR_SKILLS) return;
      setS(window.CHAR_SKILLS.getState());
      return window.CHAR_SKILLS.subscribe(setS);
    }, []);
    return s;
  }

  function useCharAttrs() {
    const [a, setA] = useState(() =>
      window.CHAR_ATTRS ? window.CHAR_ATTRS.getState() : { totals: {} }
    );
    useEffect(() => {
      if (!window.CHAR_ATTRS) return;
      setA(window.CHAR_ATTRS.getState());
      return window.CHAR_ATTRS.subscribe(setA);
    }, []);
    return a;
  }

  function useCharLevel() {
    const [lvl, setLvl] = useState(() => readCharLevel());
    useEffect(() => {
      const onChange = () => setLvl(readCharLevel());
      window.addEventListener("arton:char-changed", onChange);
      document.addEventListener("arton:char-changed", onChange);
      window.addEventListener("storage", onChange);
      return () => {
        window.removeEventListener("arton:char-changed", onChange);
        document.removeEventListener("arton:char-changed", onChange);
        window.removeEventListener("storage", onChange);
      };
    }, []);
    return lvl;
  }

  // -----------------------------------------------------------------------
  // Componentes pequenos
  // -----------------------------------------------------------------------
  function SkCorners() {
    return (
      <>
        <span className="frame-corner tl" />
        <span className="frame-corner tr" />
        <span className="frame-corner bl" />
        <span className="frame-corner br" />
      </>
    );
  }

  function ShieldIcon({ size = 13 }) {
    /* ícone de elmo/escudo — sinaliza penalidade de armadura */
    return (
      <svg
        className="sk-armor-icon"
        viewBox="0 0 24 24"
        width={size}
        height={size}
        aria-label="sofre penalidade de armadura"
      >
        <path
          d="M12 3 4 6v6c0 5.2 3.6 8.4 8 9 4.4-.6 8-3.8 8-9V6l-8-3Z"
          fill="none"
          stroke="currentColor"
          strokeWidth="1.5"
          strokeLinejoin="round"
        />
        <path
          d="M12 8v8M9 12h6"
          stroke="currentColor"
          strokeWidth="1.3"
          strokeLinecap="round"
        />
      </svg>
    );
  }

  function LockIcon({ size = 13 }) {
    return (
      <svg viewBox="0 0 24 24" width={size} height={size} aria-hidden="true">
        <path
          d="M7 10V8a5 5 0 0 1 10 0v2"
          fill="none"
          stroke="currentColor"
          strokeWidth="1.5"
        />
        <rect
          x="5" y="10" width="14" height="10" rx="2"
          fill="none" stroke="currentColor" strokeWidth="1.5"
        />
      </svg>
    );
  }

  function formatSigned(n) {
    return n >= 0 ? `+${n}` : `${n}`;
  }

  // -----------------------------------------------------------------------
  // Conflitos banner
  // -----------------------------------------------------------------------
  function ConflictsBanner({ conflicts }) {
    if (!conflicts || conflicts.length === 0) return null;
    const onResolve = () => {
      if (!window.CHAR_SKILLS) return;
      const state = window.CHAR_SKILLS.getState();
      const valid = new Set([...(state.options || [])]);
      const saved = lsRead("arton_skills") || {};
      // Só filtra o slot de classe — int_bonus aceita qualquer perícia (regra T20).
      const newChoices = (saved.choices || []).filter((s) => valid.has(s));
      const newInt     = saved.int_bonus_choices || [];
      window.CHAR_SKILLS.setChoices(newChoices, newInt);
    };
    return (
      <div className="sk-conflicts" role="alert">
        <div className="sk-conflicts-head">
          <span className="sk-conflicts-mark">⚠</span>
          <strong>Conflitos de perícia</strong>
          <span className="sk-conflicts-count">{conflicts.length}</span>
        </div>
        <p className="sk-conflicts-text">
          As perícias abaixo não pertencem à classe atual:&nbsp;
          {conflicts.map((c, i) => (
            <span key={c} className="sk-conflict-chip">
              {c}{i < conflicts.length - 1 ? "" : ""}
            </span>
          ))}
        </p>
        <button className="sk-conflicts-btn" onClick={onResolve}>
          Resolver automaticamente
        </button>
      </div>
    );
  }

  // -----------------------------------------------------------------------
  // SkillCard
  // -----------------------------------------------------------------------
  function SkillCard({ skill, state, level, attrMod }) {
    const trainedEntry = state.trained[skill.name];
    const trained = !!trainedEntry;
    const source  = trainedEntry?.source || null;

    const inClassOptions = (state.options || []).includes(skill.name);
    const classSlotsLeft = state.slots_total - state.slots_used;
    const intSlotsLeft   = state.slots_int   - state.slots_int_used;

    /* Regra T20: bônus de INT pode treinar QUALQUER perícia, mesmo fora da lista.
       - canPickClass: tem slot de classe + perícia está na lista da classe
       - canPickInt:   tem slot de INT (qualquer perícia)
       O store roteia automaticamente: classe primeiro (se aplicável), depois INT. */
    const canPickClass = !trained && inClassOptions && classSlotsLeft > 0;
    const canPickInt   = !trained && intSlotsLeft > 0;
    const canPick      = canPickClass || canPickInt;

    /* trained_only só restringe USO em jogo, não a escolha durante a criação.
       Mantemos um flag informativo para o tooltip. */
    const needsTraining = skill.trained_only && !trained;

    const bonus = calcBonus({ trained, level, attrMod });

    const meta = source ? SOURCE_META[source] : null;
    const tone = meta?.tone ||
      (canPickClass ? "pickable" :
       canPickInt   ? "pickable-int" :
       "untrained");

    const [openDesc, setOpenDesc] = useState(false);

    function toggleChoice() {
      if (!window.CHAR_SKILLS) return;
      if (trained && (source === "class_choice" || source === "int_bonus")) {
        window.CHAR_SKILLS.removeChoice(skill.name);
      } else if (canPick) {
        window.CHAR_SKILLS.addChoice(skill.name);
      }
    }

    const interactive = canPick || (trained && (source === "class_choice" || source === "int_bonus"));

    return (
      <div
        className={`sk-card sk-tone-${tone} ${trained ? "is-trained" : ""} ${interactive ? "is-interactive" : ""}`}
        role={interactive ? "button" : undefined}
        tabIndex={interactive ? 0 : -1}
        aria-pressed={interactive ? trained : undefined}
        onClick={interactive ? toggleChoice : undefined}
        onKeyDown={(e) => {
          if (interactive && (e.key === "Enter" || e.key === " ")) {
            e.preventDefault();
            toggleChoice();
          }
        }}
      >
        <span className="sk-card-stripe" aria-hidden="true" />

        {/* badge inline na sub-row, evitamos absolute pra não cortar o nome */}
        <div className="sk-card-main">
          <div className="sk-card-row">
            <span className="sk-card-name">{skill.name}</span>
            {skill.armor_penalty && (
              <span className="sk-armor" title="Sofre penalidade de armadura">
                <ShieldIcon />
              </span>
            )}
          </div>
          <div className="sk-card-sub">
            <span className="sk-card-attr">{skill.key_attribute}</span>
            {meta && (
              <span className="sk-source-badge" title={meta.label}>{meta.short}</span>
            )}
            {canPickClass && (
              <span className="sk-source-badge sk-source-badge--ghost" title="Disponível para escolha de classe">
                disponível
              </span>
            )}
            {!canPickClass && canPickInt && (
              <span className="sk-source-badge sk-source-badge--ghost" title="Treinável com bônus de Inteligência (fora da lista da classe)">
                via INT
              </span>
            )}
            {needsTraining && (
              <span
                className="sk-source-badge sk-source-badge--hint"
                title="Esta perícia só pode ser usada em jogo se treinada — não afeta a escolha aqui."
              >
                <LockIcon size={11} /> só treinada
              </span>
            )}
            {trained && !meta && (
              <span className="sk-card-status">treinada</span>
            )}
            <button
              className="sk-info-btn"
              onClick={(e) => { e.stopPropagation(); setOpenDesc(o => !o); }}
              aria-label="Ver descrição"
              aria-expanded={openDesc}
              title={openDesc ? "Fechar descrição" : "Ver descrição"}
            >ⓘ</button>
          </div>
        </div>

        <div className="sk-card-bonus">
          {formatSigned(bonus.total)}
        </div>

        {/* breakdown — sempre presente, revelado em hover/focus via CSS */}
        <div className="sk-card-tooltip" role="tooltip">
          <div className="sk-tt-formula">
            <span title="metade do nível">{`⌊${level}/2⌋ = ${bonus.half}`}</span>
            <span className="sk-tt-op">+</span>
            <span title={`mod. ${skill.key_attribute}`}>{`${skill.key_attribute} ${formatSigned(bonus.attr)}`}</span>
            {bonus.train > 0 && (<>
              <span className="sk-tt-op">+</span>
              <span title="bônus de treinamento">{`treino +${bonus.train}`}</span>
            </>)}
            <span className="sk-tt-op">=</span>
            <strong>{formatSigned(bonus.total)}</strong>
          </div>
          {needsTraining && (
            <div className="sk-tt-warn">
              <em>Só pode ser usada em jogo se treinada (não impede a escolha aqui).</em>
            </div>
          )}
          {meta && (
            <div className="sk-tt-source">
              <span className={`sk-dot sk-dot--${meta.tone}`} /> {meta.label}
            </div>
          )}
          {openDesc && skill.description && (
            <p className="sk-tt-desc">{skill.description}</p>
          )}
        </div>
      </div>
    );
  }

  // -----------------------------------------------------------------------
  // Grupo por atributo
  // -----------------------------------------------------------------------
  function AttrGroup({ attr, skills, state, level, attrMod, filter }) {
    if (!skills.length) return null;
    const filtered = filter
      ? skills.filter(s =>
          s.name.toLowerCase().includes(filter.toLowerCase()))
      : skills;
    if (!filtered.length) return null;

    /* ordena: treinadas primeiro (na ordem das fontes), depois disponíveis
       pela classe (90), depois disponíveis via INT (95), depois resto (99) */
    const intLeft = state.slots_int - state.slots_int_used;
    const rankFor = (skill) => {
      const t = state.trained[skill.name];
      if (t) return SOURCE_ORDER.indexOf(t.source);
      if ((state.options || []).includes(skill.name)) return 90;
      if (intLeft > 0) return 95;
      return 99;
    };
    const sorted = [...filtered].sort((a, b) => {
      const ra = rankFor(a);
      const rb = rankFor(b);
      if (ra !== rb) return ra - rb;
      return a.name.localeCompare(b.name, "pt-BR");
    });

    return (
      <section className="sk-attr-group">
        <header className="sk-attr-head">
          <span className="sk-attr-mark">{attr}</span>
          <span className="sk-attr-name">{ATTR_LABELS[attr]}</span>
          <span className="sk-attr-mod">{formatSigned(attrMod || 0)}</span>
          <span className="sk-attr-rule" />
        </header>
        <div className="sk-card-grid">
          {sorted.map(s => (
            <SkillCard
              key={s.id || s.name}
              skill={s}
              state={state}
              level={level}
              attrMod={attrMod}
            />
          ))}
        </div>
      </section>
    );
  }

  // -----------------------------------------------------------------------
  // Síntese (página esquerda)
  // -----------------------------------------------------------------------
  function SynthesisPage({ state, level, filter, setFilter }) {
    const trainedList = useMemo(() => {
      const arr = Object.entries(state.trained).map(([name, info]) => ({
        name, source: info.source,
      }));
      arr.sort((a, b) => {
        const ra = SOURCE_ORDER.indexOf(a.source);
        const rb = SOURCE_ORDER.indexOf(b.source);
        if (ra !== rb) return ra - rb;
        return a.name.localeCompare(b.name, "pt-BR");
      });
      return arr;
    }, [state.trained]);

    const counts = useMemo(() => {
      const c = {};
      for (const k of SOURCE_ORDER) c[k] = 0;
      for (const info of Object.values(state.trained)) c[info.source]++;
      return c;
    }, [state.trained]);

    const classSlotsTotal = state.slots_total;
    const classSlotsUsed  = state.slots_used;
    const intSlotsTotal   = state.slots_int;
    const intSlotsUsed    = state.slots_int_used;

    const hasChoicesToReset = classSlotsUsed > 0 || intSlotsUsed > 0;

    function onReset() {
      if (!window.CHAR_SKILLS) return;
      if (hasChoicesToReset && !confirm("Limpar todas as escolhas de perícia?")) return;
      window.CHAR_SKILLS.reset();
    }

    return (
      <div className="page-content sk-synth">
        <header className="page-header">
          <span className="page-eyebrow">Personagem · Perícias</span>
          <span className="page-folio">nível {level}</span>
        </header>
        <h1 className="page-title">Perícias</h1>
        <p className="page-subtitle">
          Treinamento, fonte e bônus calculado de cada perícia do personagem.
        </p>

        {/* Slots */}
        <section className="sk-slots">
          <SlotMeter
            label="Escolhas de classe"
            used={classSlotsUsed}
            total={classSlotsTotal}
            tone="class-choice"
            empty={classSlotsTotal === 0 ? "selecione uma classe" : null}
          />
          <SlotMeter
            label="Bônus de Inteligência"
            used={intSlotsUsed}
            total={intSlotsTotal}
            tone="int"
            empty={intSlotsTotal === 0 ? "sem bônus de INT" : null}
          />
        </section>

        <div className="sk-divider">
          {SOURCE_ORDER.map((k) => (
            <span key={k} className="sk-legend-item" title={SOURCE_META[k].label}>
              <span className={`sk-dot sk-dot--${SOURCE_META[k].tone}`} />
              <span className="sk-legend-label">{SOURCE_META[k].short}</span>
              <span className="sk-legend-count">{counts[k] || 0}</span>
            </span>
          ))}
        </div>

        {/* Lista de treinadas */}
        <section className="sk-trained-list">
          <h4 className="sk-section-h">
            Treinadas
            <span className="sk-section-count">{trainedList.length}</span>
          </h4>
          {trainedList.length === 0 ? (
            <p className="sk-empty">Nenhuma perícia treinada ainda.</p>
          ) : (
            <ul className="sk-trained-ul">
              {trainedList.map(t => (
                <li key={t.name} className={`sk-trained-li sk-tone-${SOURCE_META[t.source].tone}`}>
                  <span className="sk-trained-name">{t.name}</span>
                  <span className="sk-trained-src" title={SOURCE_META[t.source].label}>
                    {SOURCE_META[t.source].short}
                  </span>
                </li>
              ))}
            </ul>
          )}
        </section>

        {/* Busca */}
        <div className="sk-filter-row">
          <input
            type="search"
            className="sk-filter"
            placeholder="Filtrar perícias…"
            value={filter}
            onChange={(e) => setFilter(e.target.value)}
          />
          <button
            className="sk-reset-btn"
            onClick={onReset}
            disabled={!hasChoicesToReset}
            title={!hasChoicesToReset ? "Sem escolhas para resetar" : "Limpa class_choice + int_bonus"}
          >
            ↺ Resetar escolhas
          </button>
        </div>
      </div>
    );
  }

  function SlotMeter({ label, used, total, tone, empty }) {
    const pct = total > 0 ? Math.min(100, (used / total) * 100) : 0;
    return (
      <div className={`sk-slot-meter sk-tone-${tone}`}>
        <div className="sk-slot-head">
          <span className="sk-slot-label">{label}</span>
          <span className="sk-slot-count">
            {empty ? (
              <em>{empty}</em>
            ) : (
              <><strong>{used}</strong>/{total}</>
            )}
          </span>
        </div>
        <div className="sk-slot-bar">
          <div className="sk-slot-fill" style={{ width: `${pct}%` }} />
          {total > 0 && Array.from({ length: total - 1 }).map((_, i) => (
            <span
              key={i}
              className="sk-slot-tick"
              style={{ left: `${((i + 1) / total) * 100}%` }}
            />
          ))}
        </div>
      </div>
    );
  }

  // -----------------------------------------------------------------------
  // Grid principal (página direita)
  // -----------------------------------------------------------------------
  function GridPage({ state, level, totals, filter }) {
    const all = window.SKILLS || [];
    /* agrupa por atributo-chave */
    const byAttr = useMemo(() => {
      const m = {};
      for (const a of ATTRS) m[a] = [];
      for (const sk of all) {
        if (m[sk.key_attribute]) m[sk.key_attribute].push(sk);
        else (m._other ||= []).push(sk);
      }
      return m;
    }, [all]);

    if (!all.length) {
      return (
        <div className="page-content">
          <header className="page-header">
            <span className="page-eyebrow">Perícias</span>
            <span className="page-folio">—</span>
          </header>
          <div className="empty-state">
            <div className="ornament">·</div>
            <div>Carregando perícias…</div>
          </div>
        </div>
      );
    }

    return (
      <div className="page-content sk-grid-page">
        <header className="page-header">
          <span className="page-eyebrow">Atributos · 31 perícias</span>
          <span className="page-folio">treino +{trainingBonus(level)}</span>
        </header>
        <div className="sk-grid-scroll">
          {ATTRS.map(a => (
            <AttrGroup
              key={a}
              attr={a}
              skills={byAttr[a] || []}
              state={state}
              level={level}
              attrMod={totals?.[a] || 0}
              filter={filter}
            />
          ))}
        </div>
      </div>
    );
  }

  // -----------------------------------------------------------------------
  // ROOT
  // -----------------------------------------------------------------------
  function SkillsCreator() {
    const state = useSkillsState();
    const attrs = useCharAttrs();
    const level = useCharLevel();
    const [filter, setFilter] = useState("");

    if (!state) {
      return (
        <div className="cc-root">
          <div className="spread-frame">
            <div className="page left"><SkCorners/>
              <div className="page-content"><div className="empty-state">
                <div className="ornament">·</div><div>Carregando…</div>
              </div></div>
            </div>
            <div className="page right"><SkCorners/></div>
          </div>
        </div>
      );
    }

    const conflicts = state.conflicts || [];

    return (
      <div className="cc-root sk-root">
        {conflicts.length > 0 && <ConflictsBanner conflicts={conflicts} />}
        <div className="spread-frame">
          <div className="page left">
            <SkCorners />
            <SynthesisPage
              state={state}
              level={level}
              filter={filter}
              setFilter={setFilter}
            />
          </div>
          <div className="page right">
            <SkCorners />
            <GridPage
              state={state}
              level={level}
              totals={attrs.totals || {}}
              filter={filter}
            />
          </div>
        </div>
      </div>
    );
  }

  window.SkillsCreator = SkillsCreator;
})();
