/* global React, window */

const { useState: useStateD, useMemo: useMemoD, useEffect: useEffectD } = React;
const DIDATICOS_SUBJECTS = window.DIDATICOS_SUBJECTS;
const DIDATICOS_LANGS = window.DIDATICOS_LANGS;

// Cor por idioma (lookup)
const LANG_COLOR = Object.fromEntries(DIDATICOS_LANGS.map(l => [l.id, l.color]));
const LANG_LABEL = Object.fromEntries(DIDATICOS_LANGS.map(l => [l.id, l.label]));
const LANG_SHORT = Object.fromEntries(DIDATICOS_LANGS.map(l => [l.id, l.short]));
const SUBJ_LABEL = Object.fromEntries(DIDATICOS_SUBJECTS.map(s => [s.id, s.label]));
const SUBJ_ICON = Object.fromEntries(DIDATICOS_SUBJECTS.map(s => [s.id, s.icon]));

// Cor pastel/translúcida por idioma para fundos suaves
const langTint = (langId) => {
  const c = LANG_COLOR[langId] || "#666";
  return `${c}1a`; // 10% alpha em hex
};

// Registro de didáticos achados na busca ao vivo (GET /books/search, ver
// README-INTEGRACAO-SCOLIST.md §8) — mutável, fora do React state, pelo
// mesmo motivo do CATALOG
// em steps-curation.jsx: um didático adotado precisa continuar resolvível
// (pra capa/preço/título) mesmo depois que o usuário troca de série ou o
// resultado da busca já saiu da tela. DIDATICOS (catálogo estático) nunca
// tem esses ids, então não há colisão.
const DIDATICOS_RUNTIME = {};
function resolveDidatico(id) {
  return DIDATICOS_RUNTIME[id] || DIDATICOS.find(d => d.id === id);
}

// ============================================================
// Componente principal, quebrado em 2 passos no app
// ============================================================

// Passo 1, Ponto de partida (modo + idiomas)
function StepDidaticosConfig() {
  const { data, setData } = useApp();
  return <DidaticosIntro
    mode={data.didaticosMode}
    langs={data.didaticosLangs || ["pt"]}
    onSave={(M, L) => setData(d => ({ ...d, didaticosMode: M, didaticosLangs: L }))}
  />;
}

// Passo 1, Adoção (busca + lista por série)
function StepDidaticosBuilder() {
  const { data, setData } = useApp();
  const mode = data.didaticosMode;
  const langs = data.didaticosLangs;
  const adopted = data.didaticosAdopted || {};
  const seeded = !!data.__didaticosPastSeeded;

  // se escolheu pular ("só literatura")
  if (mode === "skip") {
    return (
      <div>
        <Heading
          eyebrow="Livros didáticos · Passo 1, Adoção"
          title="Você optou por não incluir didáticos"
          subtitle="A lista final terá apenas literatura. Pra mudar, volte ao passo anterior." />
        <div style={{ padding: 32, textAlign: "center", background: "var(--bg-soft)", border: "1px dashed var(--border)", borderRadius: 14, color: "var(--text-mute)", fontSize: 14 }}>
          Sem didáticos nesta lista. Avance pro próximo passo quando quiser.
        </div>
      </div>
    );
  }

  // se ainda não configurou, mostra aviso pra voltar
  if (!mode || !langs) {
    return (
      <div>
        <Heading
          eyebrow="Livros didáticos · Passo 1, Adoção"
          title="Escolha um ponto de partida primeiro"
          subtitle="Volte ao passo anterior pra escolher como começar." />
      </div>
    );
  }

  // seed "lista do ano passado", uma vez
  React.useEffect(() => {
    if (mode !== "past" || seeded) return;
    const past = seedPastDidaticos(langs, resolveSeriesList(data));
    setData(d => ({ ...d, didaticosAdopted: past, __didaticosPastSeeded: true }));
    // eslint-disable-next-line
  }, [mode, seeded]);

  return <DidaticosBuilder
    mode={mode}
    langs={langs}
    adopted={adopted}
    setAdopted={(updater) => setData(d => ({ ...d, didaticosAdopted: typeof updater === "function" ? updater(d.didaticosAdopted || {}) : updater }))}
    onResetConfig={() => setData(d => ({ ...d, didaticosMode: undefined, didaticosLangs: undefined, didaticosAdopted: {}, __didaticosPastSeeded: false }))}
  />;
}

// Wrapper legado (não usado mais no fluxo, mas mantido pra compatibilidade)
function StepDidaticos() {
  const { data } = useApp();
  if (!data.didaticosMode || !data.didaticosLangs) {
    return <StepDidaticosConfig/>;
  }
  return <StepDidaticosBuilder/>;
}

// ============================================================
// Seed: "lista do ano passado", pega a coleção mais comum
// (Moderna/Ática Buriti+Ápis pra fund1, Araribá+Bernoulli pra fund2,
//  Conexões pra EM) por disciplina principal e por idioma.
// ============================================================
// `seriesList` é a lista de séries de verdade da escola (Passo 1, ver
// resolveSeriesList em shared.jsx) — cada posição pode ser Fund1/Fund2/EM
// (renomeado ou não), Educação Infantil, ou uma série 100% customizada. O
// catálogo estático de didáticos (window.DIDATICOS) só conhece os nomes
// CANÔNICOS ("6º ano" etc), então a busca usa o canônico correspondente à
// série (window.canonicalIndexOf/SERIES_LIST, shared.jsx), não o rótulo
// exibido. Séries sem canônico reconhecido (Infantil, nome customizado) não
// têm coleção padrão pra herdar e ficam sem seed automático.
function seedPastDidaticos(langs, seriesList) {
  const adopted = {};
  // Para cada série, pega 1 didático por disciplina principal disponível, no idioma configurado
  // Heurística: prioriza Moderna > Ática > FTD > outros, e prefere coleções que cobrem a série
  const PREF_PUBLISHERS = ["Moderna", "Ática", "FTD", "Editora Bernoulli", "Pitágoras", "Cambridge", "Pearson", "Macmillan", "Oxford"];
  const CORE_SUBJECTS_FUND1 = ["portugues", "matematica", "ciencias", "historia", "geografia"];
  const CORE_SUBJECTS_FUND2 = ["portugues", "matematica", "ciencias", "historia", "geografia"];
  const CORE_SUBJECTS_EM = ["portugues", "matematica", "fisica", "quimica", "biologia", "historia", "geografia"];

  (seriesList || []).forEach((series, idx) => {
    const canonicalIdx = window.canonicalIndexOf ? window.canonicalIndexOf(series) : -1;
    const canonicalName = canonicalIdx >= 0 ? window.SERIES_LIST[canonicalIdx] : null;
    if (!canonicalName) { adopted[idx] = []; return; }
    const subjects = canonicalIdx <= 4 ? CORE_SUBJECTS_FUND1
      : canonicalIdx <= 8 ? CORE_SUBJECTS_FUND2
      : CORE_SUBJECTS_EM;
    const picks = [];
    subjects.forEach(subj => {
      // Encontra primeiro item PT que cobre série + disciplina
      const candidates = window.DIDATICOS.filter(d =>
        d.subject === subj && d.lang === "pt" && d.series.includes(canonicalName)
      ).sort((a, b) => {
        const ai = PREF_PUBLISHERS.indexOf(a.publisher);
        const bi = PREF_PUBLISHERS.indexOf(b.publisher);
        return (ai === -1 ? 99 : ai) - (bi === -1 ? 99 : bi);
      });
      if (candidates[0]) picks.push({ itemId: candidates[0].id });
    });
    // Adiciona inglês se a escola tem EN configurado (1 livro de inglês por série)
    if (langs.includes("en")) {
      const en = window.DIDATICOS.find(d => d.subject === "ingles" && d.lang === "en" && d.series.includes(canonicalName));
      if (en) picks.push({ itemId: en.id });
    }
    adopted[idx] = picks;
  });
  return adopted;
}

// ============================================================
// Tela de configuração inicial, Ponto de partida
// ============================================================
function DidaticosIntro({ mode, langs, onSave }) {
  const [M, setM] = useStateD(mode);
  const [L, setL] = useStateD(langs && langs.length ? langs : ["pt"]);

  const toggleLang = id => {
    if (id === "pt") return; // PT obrigatório
    setL(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]);
  };

  const canAdvance = M && (M === "skip" || L.length > 0);
  const needsLangs = M && M !== "skip";

  // Auto-save toda mudança, fluxo global tem botão Continuar
  React.useEffect(() => {
    if (M) onSave(M, L);
  }, [M, L.join(",")]);

  return (
    <div>
      <PremiumHeader
        image="assets/lex-didaticos.png"
        imageAlt="Lex em modo didáticos"
        eyebrow="Livros didáticos · Passo 1, Ponto de partida"
        title="De onde a gente começa com os didáticos?"
        subtitle="Aqui você adiciona os didáticos que a escola adota. Pode pular essa etapa ou montar a lista do zero."
      />

      {/* 2 cards de ponto de partida — o card "usar lista do ano passado"
          foi removido (item 15, TAREFAS-JOANA-2026-08-21.md): ele prometia
          puxar os didáticos do ano anterior, mas na prática só chutava uma
          coleção por heurística de editora (seedPastDidaticos), sem nenhum
          reconhecimento real de ISBN — pedido explícito da Joana era
          reconhecer ISBN de verdade ou, se for difícil, tirar o quadrado. */}
      <div style={{ marginTop: 24, display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 14 }}>
        {[
          {
            id: "skip",
            icon: "📚",
            title: "Só literatura",
            sub: "Pular esta etapa. A lista final terá apenas literatura, sem didáticos.",
          },
          {
            id: "scratch",
            icon: "✏️",
            title: "Montar do zero",
            sub: "Busca livre por didático, série a série. Indicado se a escola está revendo o material.",
          },
        ].map(opt => {
          const selected = opt.id === M;
          return (
            <button key={opt.id} onClick={() => setM(opt.id)} style={{
              padding: "20px 18px", textAlign: "left",
              background: selected ? "var(--teal-soft, #e7f4f5)" : "#fff",
              border: selected ? "1.5px solid var(--teal-dark)" : "1px solid var(--border)",
              borderRadius: 14, cursor: "pointer",
              boxShadow: selected ? "var(--shadow-md)" : "var(--shadow-sm)",
              transition: "all .15s",
              display: "flex", flexDirection: "column", gap: 8,
            }}>
              <div style={{ fontSize: 28 }}>{opt.icon}</div>
              <div style={{ fontSize: 15, fontWeight: 700, color: "var(--text)" }}>{opt.title}</div>
              <div style={{ fontSize: 13, color: "var(--text-mute)", lineHeight: 1.45 }}>{opt.sub}</div>
            </button>
          );
        })}
      </div>

      {/* Idiomas, só aparece quando modo precisa de busca */}
      {needsLangs && (
        <div style={{ marginTop: 24, background: "#fff", border: "1px solid var(--border)", borderRadius: 14, padding: 22, boxShadow: "var(--shadow-sm)" }}>
          <div style={{ fontSize: 12, fontWeight: 700, color: "var(--teal-dark)", textTransform: "uppercase", letterSpacing: 1 }}>
            Idiomas que a escola trabalha
          </div>
          <div style={{ fontSize: 13, color: "var(--text-mute)", marginTop: 6, lineHeight: 1.5 }}>
            Liga só os idiomas dos quais vocês adotam material didático. Português é sempre incluído.
          </div>
          <div style={{ marginTop: 16, display: "flex", flexWrap: "wrap", gap: 8 }}>
            {DIDATICOS_LANGS.map(lg => {
              const on = L.includes(lg.id);
              const locked = lg.id === "pt";
              return (
                <button key={lg.id} onClick={() => toggleLang(lg.id)} disabled={locked}
                  style={{
                    padding: "10px 14px", borderRadius: 10,
                    border: on ? `1.5px solid ${lg.color}` : "1px solid var(--border)",
                    background: on ? langTint(lg.id) : "#fff",
                    color: on ? lg.color : "var(--text-mute)",
                    cursor: locked ? "default" : "pointer",
                    fontSize: 13.5, fontWeight: 700,
                    display: "flex", alignItems: "center", gap: 8,
                    opacity: locked ? 0.95 : 1,
                  }}>
                  <span style={{
                    width: 22, height: 22, borderRadius: 5,
                    background: on ? lg.color : "var(--bg-light)",
                    color: on ? "#fff" : "var(--text-mute)",
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    fontSize: 10, fontWeight: 800,
                  }}>{lg.short}</span>
                  {lg.label}
                  {locked && <span style={{ fontSize: 10, opacity: 0.7, fontWeight: 500 }}>· obrigatório</span>}
                </button>
              );
            })}
          </div>
        </div>
      )}

    </div>
  );
}

// ============================================================
// Tela de adoção (search + lista)
// ============================================================
function DidaticosBuilder({ langs, adopted, setAdopted, onResetConfig }) {
  const { data } = useApp();
  // Séries de verdade da escola (Passo 1), não a lista fixa de 12.
  const activeSeries = resolveSeriesList(data);
  const [seriesIdx, setSeriesIdx] = useStateD(0);
  const [query, setQuery] = useStateD("");
  // filtros: começam todos os idiomas configurados ligados, todas as disciplinas
  const [langFilter, setLangFilter] = useStateD(langs);
  const [subjFilter, setSubjFilter] = useStateD(null); // null = todas

  // sempre que muda config, reset langFilter
  useEffectD(() => { setLangFilter(langs); }, [langs.join(",")]);

  const series = activeSeries[seriesIdx]; // rótulo de exibição (o nome real cadastrado pela escola)
  // O catálogo estático de didáticos (DIDATICOS) só conhece nomes canônicos
  // ("6º ano" etc) — sem isso, uma série renomeada ou Educação Infantil
  // nunca bateria com `item.series.includes(...)` abaixo.
  const canonicalSeries = window.inferCanonicalSeriesName ? window.inferCanonicalSeriesName(series) : null;
  const adoptedHere = adopted[seriesIdx] || [];

  // adopted unique items per series, pra evitar duplicar mesmo título
  const isAdopted = (id) => adoptedHere.some(a => a.itemId === id);

  // disciplinas duplicadas nesta série
  const adoptedSubjects = adoptedHere.map(a => {
    const item = resolveDidatico(a.itemId);
    return item?.subject;
  });
  const isDupSubject = (subj) => !!subj && adoptedSubjects.filter(s => s === subj).length >= 1;

  // Busca ao vivo na base compartilhada (GET /books/search, mesmo endpoint
  // da curadoria literária — a base não tem coluna de tipo de material pra
  // diferenciar didático, ver README-INTEGRACAO-SCOLIST.md §8), além do
  // catálogo estático (curadoria própria de coleções/preço por série).
  // Debounce de 350ms, mesmo padrão do item 2.
  const [liveResults, setLiveResults] = useStateD([]);
  const [liveLoading, setLiveLoading] = useStateD(false);
  useEffectD(() => {
    const q = query.trim();
    if (q.length < 2 || !window.ScolistAPI || typeof window.ScolistAPI.searchDidaticBooks !== "function") {
      setLiveResults([]);
      setLiveLoading(false);
      return;
    }
    let cancelled = false;
    setLiveLoading(true);
    const handle = setTimeout(async () => {
      try {
        const raw = await window.ScolistAPI.searchDidaticBooks(q);
        if (cancelled) return;
        const normalized = raw.map((book) => {
          // Faz merge com uma entrada já existente (não sobrescreve) — o
          // mesmo livro pode reaparecer numa busca depois que o usuário já
          // adotou ele numa outra série; sobrescrever perderia o preço
          // guardado daquela série (o card de "adotados" ficaria mostrando
          // R$ 0 pra um item que já foi confirmado antes).
          const existing = DIDATICOS_RUNTIME[book.id];
          const item = {
            id: book.id,
            kind: "titulo",
            title: book.title,
            publisher: book.publisher,
            lang: book.lang,
            subject: null,
            format: null,
            series: existing ? Array.from(new Set([...existing.series, series])) : [series],
            priceBySeries: { ...(existing && existing.priceBySeries), [series]: book.price || 0 },
            // era `book.coverImageUrl`, mas o mapper de busca (api.js,
            // mapBookSearchResultToItem) devolve o campo como `imageUrl` —
            // a capa nunca carregava porque o nome nunca batia (bug
            // reportado pela Joana, reunião 26/08/2026: "não sei porque
            // nenhuma capa aparece" nos didáticos).
            coverImageUrl: book.imageUrl || (existing && existing.coverImageUrl) || null,
          };
          DIDATICOS_RUNTIME[item.id] = item;
          return item;
        });
        setLiveResults(normalized);
      } catch (err) {
        if (!cancelled) setLiveResults([]);
      } finally {
        if (!cancelled) setLiveLoading(false);
      }
    }, 350);
    return () => { cancelled = true; clearTimeout(handle); };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [query, series]);

  // resultados filtrados (catálogo estático + busca ao vivo)
  const results = useMemoD(() => {
    const q = query.trim().toLowerCase();
    const staticMatches = DIDATICOS.filter(item => {
      // configurou esse idioma?
      if (!langs.includes(item.lang)) return false;
      // filtro idioma
      if (!langFilter.includes(item.lang)) return false;
      // filtro disciplina
      if (subjFilter && item.subject !== subjFilter) return false;
      // série coberta? (pelo nome canônico — ver comentário acima de canonicalSeries)
      if (!canonicalSeries || !item.series.includes(canonicalSeries)) return false;
      // search
      if (q) {
        const hay = `${item.title} ${item.publisher} ${SUBJ_LABEL[item.subject] || ""} ${LANG_LABEL[item.lang] || ""}`.toLowerCase();
        if (!hay.includes(q)) return false;
      }
      return true;
    });
    const seenIds = new Set(staticMatches.map(i => i.id));
    const liveMatches = liveResults.filter(item =>
      langs.includes(item.lang) && langFilter.includes(item.lang) &&
      (!subjFilter) && !seenIds.has(item.id)
    );
    return [...staticMatches, ...liveMatches];
  }, [query, langFilter, subjFilter, series, langs, liveResults]);

  // Adotar sempre só na série atual, direto — igual o "adicionar" da
  // literatura. Antes, coleções (kind "colecao") abriam um dialog
  // oferecendo espalhar o título nas outras séries do segmento inteiro
  // de uma vez ("Adotar em todo o Fundamental I", etc). A Joana pediu pra
  // tirar isso (reunião 26/08/2026): sem uma tabela de "qual coleção
  // pertence a qual escola", presumir que a coleção inteira da editora
  // deveria entrar em todas as séries do segmento é arriscado — o volume
  // certo por série pode nem ser esse que a escola adotou. Cada série
  // continua tendo que ser escolhida manualmente, uma de cada vez.
  const adopt = (item) => {
    addToSeries(item, [series]);
  };

  const addToSeries = (item, seriesList) => {
    setAdopted(prev => {
      const next = { ...prev };
      seriesList.forEach(s => {
        const idx = activeSeries.indexOf(s);
        if (idx < 0) return;
        const cur = next[idx] || [];
        if (cur.some(a => a.itemId === item.id)) return;
        next[idx] = [...cur, { itemId: item.id }];
      });
      return next;
    });
  };

  const remove = (itemId) => {
    setAdopted(prev => ({
      ...prev,
      [seriesIdx]: (prev[seriesIdx] || []).filter(a => a.itemId !== itemId),
    }));
  };

  // contagem total
  const totalAdopted = Object.values(adopted).reduce((sum, arr) => sum + arr.length, 0);

  // série visual
  const ChipSeries = ({ s, i }) => {
    const cnt = (adopted[i] || []).length;
    const filled = cnt > 0;
    const active = i === seriesIdx;
    return (
      <button onClick={() => setSeriesIdx(i)} style={{
        padding: "10px 8px", borderRadius: 8,
        border: active ? "1.5px solid var(--teal-dark)" : "1px solid var(--border)",
        background: active ? "var(--teal-dark)" : filled ? "#e7f4f5" : "#fff",
        color: active ? "#fff" : "var(--text)",
        fontSize: 12, fontWeight: 700, cursor: "pointer",
        position: "relative", textAlign: "center", lineHeight: 1.2,
        minWidth: 0,
      }}>
        {s}
        <div style={{ fontSize: 10, fontWeight: 600, marginTop: 2, opacity: active ? 0.9 : 0.7 }}>
          {cnt}
        </div>
      </button>
    );
  };

  return (
    <div>
      <Heading
        eyebrow="Livros didáticos · Passo 1, Adoção"
        title="Adicione os didáticos adotados pela escola"
        subtitle="Por série, busque e adote livro a livro, ou adote uma coleção em várias séries de uma vez."
      />

      {/* topo: configuração resumida + reset + total */}
      <div style={{ marginTop: 18, display: "flex", justifyContent: "space-between", alignItems: "center", gap: 14, padding: "12px 16px", background: "var(--bg-soft)", border: "1px solid var(--border)", borderRadius: 12 }}>
        <div style={{ display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" }}>
          <div>
            <div style={{ fontSize: 11, color: "var(--text-mute)", fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.6 }}>Idiomas</div>
            <div style={{ display: "flex", gap: 4, marginTop: 4 }}>
              {langs.map(id => (
                <span key={id} style={{
                  padding: "3px 8px", borderRadius: 5, fontSize: 11, fontWeight: 800, letterSpacing: 0.4,
                  background: LANG_COLOR[id], color: "#fff",
                }}>{LANG_SHORT[id]}</span>
              ))}
            </div>
          </div>
          <div style={{ width: 1, height: 28, background: "var(--border)" }}/>
          <div>
            <div style={{ fontSize: 11, color: "var(--text-mute)", fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.6 }}>Adotados no total</div>
            <div style={{ fontSize: 14, fontWeight: 700, color: "var(--teal-dark)", marginTop: 4 }}>
              {totalAdopted} {totalAdopted === 1 ? "didático" : "didáticos"}
            </div>
          </div>
        </div>
        <button onClick={onResetConfig} style={{
          padding: "8px 12px", background: "transparent", color: "var(--text-mute)",
          border: "1px solid var(--border)", borderRadius: 8, fontSize: 12, fontWeight: 600,
          cursor: "pointer",
        }}>↺ Refazer configuração</button>
      </div>

      {/* Seletor de série */}
      <div style={{ marginTop: 16 }}>
        <div style={{ display: "grid", gridTemplateColumns: `repeat(${activeSeries.length}, 1fr)`, gap: 6 }}>
          {activeSeries.map((s, i) => <ChipSeries key={s} s={s} i={i}/>)}
        </div>
      </div>

      {/* Layout 2-col: search/results à esquerda · adotados à direita */}
      <div style={{ marginTop: 18, display: "grid", gridTemplateColumns: "1.5fr 1fr", gap: 18 }}>

        {/* COLUNA ESQUERDA, busca */}
        <div>
          {/* Search bar */}
          <div style={{ background: "#fff", border: "1px solid var(--border)", borderRadius: 14, padding: 14, boxShadow: "var(--shadow-sm)" }}>
            <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
              <span style={{ fontSize: 18 }}>🔍</span>
              <input
                value={query}
                onChange={e => setQuery(e.target.value)}
                placeholder={`Buscar didáticos para ${series}…  (ex: matemática, Bernoulli, Cambridge)`}
                style={{
                  flex: 1, border: "none", outline: "none",
                  fontSize: 14, fontFamily: "inherit",
                  background: "transparent",
                }}
              />
              {query && (
                <button onClick={() => setQuery("")} style={{
                  background: "transparent", border: "none", color: "var(--text-mute)",
                  fontSize: 16, cursor: "pointer", padding: "0 4px",
                }}>×</button>
              )}
            </div>

            {/* filtros */}
            <div style={{ marginTop: 12, paddingTop: 12, borderTop: "1px dashed var(--border)", display: "flex", flexDirection: "column", gap: 10 }}>
              {/* idioma, só aparece se há mais de 1 idioma configurado */}
              {langs.length > 1 && (
                <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
                  <span style={{ fontSize: 11, fontWeight: 700, color: "var(--text-mute)", textTransform: "uppercase", letterSpacing: 0.6, minWidth: 70 }}>Idioma</span>
                  <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
                    {langs.map(id => {
                      const on = langFilter.includes(id);
                      const lg = DIDATICOS_LANGS.find(l => l.id === id);
                      return (
                        <button key={id} onClick={() => setLangFilter(prev => on ? prev.filter(x => x !== id) : [...prev, id])} style={{
                          padding: "5px 10px", borderRadius: 5, fontSize: 11, fontWeight: 700, letterSpacing: 0.4,
                          background: on ? lg.color : "transparent",
                          color: on ? "#fff" : "var(--text-mute)",
                          border: on ? "none" : "1px solid var(--border)",
                          cursor: "pointer",
                        }}>{lg.short}</button>
                      );
                    })}
                  </div>
                </div>
              )}

              {/* disciplina */}
              <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                <span style={{ fontSize: 11, fontWeight: 700, color: "var(--text-mute)", textTransform: "uppercase", letterSpacing: 0.6, minWidth: 70 }}>Disciplina</span>
                <select value={subjFilter || ""} onChange={e => setSubjFilter(e.target.value || null)} style={{
                  padding: "5px 8px", border: "1px solid var(--border)", borderRadius: 6,
                  fontSize: 12, fontFamily: "inherit", background: "#fff", color: "var(--text)",
                  cursor: "pointer", flex: 1, maxWidth: 280,
                }}>
                  <option value="">Todas as disciplinas</option>
                  {DIDATICOS_SUBJECTS.map(s => (
                    <option key={s.id} value={s.id}>{s.icon}  {s.label}</option>
                  ))}
                </select>
              </div>
            </div>
          </div>

          {/* Resultados */}
          <div style={{ marginTop: 14 }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 10 }}>
              <div style={{ fontSize: 12, fontWeight: 700, color: "var(--teal-dark)", textTransform: "uppercase", letterSpacing: 1 }}>
                {results.length} resultado{results.length !== 1 ? "s" : ""} para {series}
              </div>
              {liveLoading && (
                <div style={{ fontSize: 11, color: "var(--text-mute)", fontWeight: 600 }}>
                  Buscando…
                </div>
              )}
            </div>
            {results.length === 0 ? (
              <div style={{ padding: 32, textAlign: "center", background: "var(--bg-light)", borderRadius: 12, color: "var(--text-mute)", fontSize: 13.5 }}>
                Nenhum didático encontrado com esses filtros.
                <br/><span style={{ fontSize: 12 }}>Experimente limpar a busca ou ampliar os filtros.</span>
              </div>
            ) : (
              <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                {results.map(item => <ResultCard key={item.id} item={item} series={series} canonicalSeries={canonicalSeries}
                  isAdopted={isAdopted(item.id)}
                  isDupSubject={isDupSubject(item.subject) && !isAdopted(item.id)}
                  onAdopt={() => adopt(item)}
                  onRemove={() => remove(item.id)}
                />)}
              </div>
            )}
          </div>
        </div>

        {/* COLUNA DIREITA, adotados nesta série */}
        <div>
          <div style={{ position: "sticky", top: 12, background: "#fff", border: "1px solid var(--border)", borderRadius: 14, padding: 16, boxShadow: "var(--shadow-sm)" }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 12 }}>
              <div>
                <div style={{ fontSize: 11, color: "var(--text-mute)", fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.6 }}>Adotados em</div>
                <div style={{ fontSize: 18, fontWeight: 800, color: "var(--text)", marginTop: 2, letterSpacing: -0.3 }}>{series}</div>
              </div>
              <div style={{ textAlign: "right" }}>
                <div style={{ fontSize: 22, fontWeight: 800, color: adoptedHere.length > 0 ? "var(--teal-dark)" : "var(--text-mute)", letterSpacing: -0.5 }}>
                  {adoptedHere.length}
                </div>
                <div style={{ fontSize: 10, color: "var(--text-mute)", marginTop: 2 }}>{adoptedHere.length === 1 ? "livro" : "livros"}</div>
              </div>
            </div>

            {adoptedHere.length === 0 ? (
              <div style={{ padding: "24px 12px", textAlign: "center", color: "var(--text-mute)", fontSize: 13, lineHeight: 1.5 }}>
                Nenhum didático adotado para {series} ainda.
                <br/><span style={{ fontSize: 11.5 }}>Use o search ao lado pra adicionar.</span>
              </div>
            ) : (
              <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                {adoptedHere.map((a, i) => {
                  const item = resolveDidatico(a.itemId);
                  if (!item) return null;
                  // priceBySeries: item de busca ao vivo é chaveado pelo rótulo de
                  // exibição (self-consistente, ver comentário lá em cima); item do
                  // catálogo estático só conhece o nome canônico — tenta os dois.
                  const price = item.priceBySeries[series] || (canonicalSeries && item.priceBySeries[canonicalSeries]) || 0;
                  return (
                    <div key={i} style={{
                      display: "flex", gap: 10, alignItems: "center",
                      padding: "8px 10px", background: "var(--bg-light)",
                      borderRadius: 8, fontSize: 12.5,
                    }}>
                      <DidaticoCover item={item} w={26} h={36}/>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontWeight: 700, color: "var(--text)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{item.title}</div>
                        <div style={{ fontSize: 10.5, color: "var(--text-mute)", marginTop: 1 }}>
                          {SUBJ_ICON[item.subject]} {SUBJ_LABEL[item.subject]} · {item.publisher}
                        </div>
                      </div>
                      <div style={{ fontSize: 11.5, fontWeight: 800, color: "var(--teal-dark)", whiteSpace: "nowrap" }}>R$ {price.toFixed(0)}</div>
                      <button onClick={() => remove(item.id)} style={{
                        background: "transparent", border: "none", color: "var(--text-mute)",
                        cursor: "pointer", fontSize: 16, padding: 2, lineHeight: 1,
                      }} title="Remover">×</button>
                    </div>
                  );
                })}
                {/* Total série */}
                <div style={{ marginTop: 6, padding: "10px 10px 4px", borderTop: "1px dashed var(--border)", display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
                  <span style={{ fontSize: 12, color: "var(--text-mute)", fontWeight: 600 }}>Subtotal {series}</span>
                  <span style={{ fontSize: 16, fontWeight: 800, color: "var(--teal-dark)" }}>
                    R$ {adoptedHere.reduce((s, a) => {
                      const it = resolveDidatico(a.itemId);
                      return s + (it ? (it.priceBySeries[series] || (canonicalSeries && it.priceBySeries[canonicalSeries]) || 0) : 0);
                    }, 0).toFixed(2)}
                  </span>
                </div>
              </div>
            )}

            {/* duplicidade aviso */}
            {(() => {
              const counts = {};
              adoptedHere.forEach(a => {
                const it = resolveDidatico(a.itemId);
                if (it) counts[it.subject] = (counts[it.subject] || 0) + 1;
              });
              const dups = Object.entries(counts).filter(([_, n]) => n > 1);
              if (dups.length === 0) return null;
              return (
                <div style={{ marginTop: 10, padding: "8px 10px", background: "#fff7e6", border: "1px solid #f0c878", borderRadius: 8, fontSize: 11.5, color: "#8b5a1a", lineHeight: 1.4 }}>
                  <strong>2+ livros</strong> da mesma disciplina nesta série: {dups.map(([s]) => SUBJ_LABEL[s]).join(", ")}. Pode ser proposital (escola bilíngue), só te aviso.
                </div>
              );
            })()}
          </div>
        </div>
      </div>
    </div>
  );
}

// ============================================================
// Capa estilizada do didático, placeholder de livro escolar
// (barras horizontais + título + faixa de idioma + ícone de disciplina)
// ============================================================
function DidaticoCover({ item, w = 56, h = 78 }) {
  const langColor = LANG_COLOR[item.lang] || "#888";
  const subjIcon = SUBJ_ICON[item.subject] || "📘";
  const isMini = w < 40;
  // Cor de fundo da capa baseada na editora pra ter variedade visual
  const PUBLISHER_BG = {
    "Moderna": "#1e3a5f",
    "Ática": "#c4302b",
    "FTD": "#0f6e3e",
    "Editora do Brasil": "#7a2e8e",
    "Editora Bernoulli": "#1a2e5c",
    "Pitágoras": "#d4801f",
    "Cambridge": "#7a1f3b",
    "Pearson": "#0099a8",
    "Macmillan": "#bd2c2c",
    "Oxford": "#002147",
    "Salamandra": "#d63a2f",
    "SM": "#0066b3",
    "Positivo": "#e8741e",
    "Saraiva": "#0058a6",
    "Edebê": "#009b6b",
    "Richmond": "#5a2e8a",
    "Eli": "#0d8aa9",
  };
  const bg = PUBLISHER_BG[item.publisher] || "#3a4a5c";

  // Livro vindo de busca ao vivo (quando disponível) já traz capa de
  // verdade — prioriza sobre a arte sintética do catálogo estático.
  if (item.coverImageUrl) {
    return (
      <img
        src={item.coverImageUrl}
        alt={item.title}
        style={{
          width: w, height: h, flexShrink: 0,
          objectFit: "cover", borderRadius: isMini ? 3 : 4,
          boxShadow: "0 2px 6px rgba(0,0,0,0.18)",
        }}
      />
    );
  }

  if (isMini) {
    // Versão mini: só barra de idioma + ícone da disciplina
    return (
      <div style={{
        width: w, height: h, flexShrink: 0,
        borderRadius: 3,
        background: bg,
        position: "relative", overflow: "hidden",
        boxShadow: "0 1px 3px rgba(0,0,0,0.18), inset -1px 0 0 rgba(0,0,0,0.15)",
        display: "flex", flexDirection: "column",
      }}>
        <div style={{ height: 6, background: langColor }}/>
        <div style={{
          flex: 1, display: "flex", alignItems: "center", justifyContent: "center",
          fontSize: 14, lineHeight: 1,
        }}>{subjIcon}</div>
      </div>
    );
  }

  // Trunca título pra caber na capa
  const titleParts = item.title.split(/\s+/);
  const firstWords = titleParts.slice(0, 2).join(" ");
  const restWord = titleParts.slice(2, 4).join(" ");

  return (
    <div style={{
      width: w, height: h, flexShrink: 0,
      borderRadius: 4,
      background: bg,
      position: "relative", overflow: "hidden",
      boxShadow: "0 2px 6px rgba(0,0,0,0.18), inset -2px 0 0 rgba(0,0,0,0.15)",
      display: "flex", flexDirection: "column",
      fontFamily: "'Inter', sans-serif",
    }}>
      {/* faixa superior com idioma */}
      <div style={{
        height: 12, background: langColor,
        display: "flex", alignItems: "center", justifyContent: "center",
        fontSize: 7, fontWeight: 800, color: "#fff", letterSpacing: 0.6,
      }}>
        {LANG_SHORT[item.lang]}
      </div>

      {/* área central, título */}
      <div style={{
        flex: 1, padding: "6px 5px",
        display: "flex", flexDirection: "column",
        justifyContent: "center", alignItems: "center",
        textAlign: "center",
      }}>
        <div style={{
          fontSize: 8.5, fontWeight: 800, color: "#fff",
          lineHeight: 1.05, letterSpacing: -0.1,
          textShadow: "0 1px 2px rgba(0,0,0,0.3)",
        }}>{firstWords}</div>
        {restWord && (
          <div style={{
            fontSize: 7, fontWeight: 600, color: "rgba(255,255,255,0.85)",
            lineHeight: 1.1, marginTop: 2,
          }}>{restWord}</div>
        )}
      </div>

      {/* ícone de disciplina */}
      <div style={{
        position: "absolute", bottom: 4, right: 4,
        fontSize: 12, opacity: 0.95,
      }}>{subjIcon}</div>

      {/* selo da editora */}
      <div style={{
        height: 10, background: "rgba(255,255,255,0.15)",
        display: "flex", alignItems: "center", justifyContent: "center",
        fontSize: 6, fontWeight: 700, color: "rgba(255,255,255,0.92)",
        letterSpacing: 0.4, textTransform: "uppercase",
      }}>
        {item.publisher.length > 12 ? item.publisher.slice(0, 11) + "…" : item.publisher}
      </div>
    </div>
  );
}

// ============================================================
// Card de resultado
// ============================================================
function ResultCard({ item, series, canonicalSeries, isAdopted, isDupSubject, onAdopt, onRemove }) {
  // priceBySeries: item de busca ao vivo é chaveado pelo rótulo de exibição
  // (self-consistente); item do catálogo estático só conhece o nome
  // canônico da série — tenta os dois.
  const price = item.priceBySeries[series] || (canonicalSeries && item.priceBySeries[canonicalSeries]) || 0;
  const seriesCount = item.series.length;
  const isCol = item.kind === "colecao" && seriesCount > 1;

  return (
    <div style={{
      display: "flex", gap: 12, alignItems: "stretch",
      padding: 12, background: "#fff",
      border: isAdopted ? "1.5px solid var(--teal)" : "1px solid var(--border)",
      borderRadius: 12, boxShadow: "var(--shadow-sm)",
    }}>
      {/* Capa estilizada do didático */}
      <DidaticoCover item={item} />

      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap", marginBottom: 4 }}>
          <span style={{
            padding: "2px 7px", borderRadius: 4, fontSize: 10, fontWeight: 800, letterSpacing: 0.4,
            background: LANG_COLOR[item.lang], color: "#fff",
          }}>{LANG_SHORT[item.lang]}</span>
          <span style={{ fontSize: 11, color: "var(--text-mute)", fontWeight: 600 }}>
            {item.subject ? <>{SUBJ_ICON[item.subject]} {SUBJ_LABEL[item.subject]}</> : "Disciplina não informada"}
          </span>
          {item.badge && (
            <span style={{
              padding: "2px 7px", borderRadius: 10, fontSize: 10, fontWeight: 700, letterSpacing: 0.3,
              background: "var(--bg-light)", color: "var(--text)",
            }}>{item.badge}</span>
          )}
          {isCol && (
            <span style={{
              padding: "2px 7px", borderRadius: 10, fontSize: 10, fontWeight: 700,
              background: "#eef3ff", color: "#2c4ffc",
            }}>📚 Coleção · {seriesCount} séries</span>
          )}
        </div>
        <div style={{ fontSize: 14, fontWeight: 700, color: "var(--text)", lineHeight: 1.3 }}>{item.title}</div>
        <div style={{ fontSize: 12, color: "var(--text-mute)", marginTop: 2 }}>
          {item.publisher}{item.format ? ` · ${item.format === "hibrido" ? "físico + digital" : item.format}` : ""}
        </div>
        {isDupSubject && item.subject && (
          <div style={{ marginTop: 6, fontSize: 11.5, color: "#8b5a1a" }}>
            ⚠ Você já tem {SUBJ_LABEL[item.subject]} adotada nesta série
          </div>
        )}
      </div>

      <div style={{ display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 8, justifyContent: "space-between" }}>
        <div style={{ textAlign: "right" }}>
          <div style={{ fontSize: 18, fontWeight: 800, color: "var(--teal-dark)", letterSpacing: -0.3, lineHeight: 1 }}>
            R$ {price.toFixed(0)}
          </div>
          <div style={{ fontSize: 10, color: "var(--text-mute)" }}>preço de capa</div>
        </div>
        {isAdopted ? (
          <button onClick={onRemove} style={{
            padding: "6px 12px", background: "var(--bg-light)", color: "var(--text-mute)",
            border: "1px solid var(--border)", borderRadius: 6, fontSize: 12, fontWeight: 700,
            cursor: "pointer", whiteSpace: "nowrap",
          }}>✓ Adotado</button>
        ) : (
          <button onClick={onAdopt} style={{
            padding: "6px 14px", background: "var(--teal-dark)", color: "#fff",
            border: "none", borderRadius: 6, fontSize: 12, fontWeight: 700,
            cursor: "pointer", whiteSpace: "nowrap",
          }}>+ Adotar</button>
        )}
      </div>
    </div>
  );
}

// ============================================================
// Dialog: adotar coleção em várias séries de uma vez. Não é mais chamado
// (ver `adopt()` acima) desde que a Joana pediu pra tirar o "adotar em
// todo o segmento" (reunião 26/08/2026) — mantido aqui sem uso caso a
// decisão volte atrás com uma fonte de dados confiável de coleção→escola.
// ============================================================
function CollectionDialog({ item, applicableSeries, currentSeries, onConfirm, onCancel }) {
  const [mode, setMode] = useStateD("all"); // "all" | "current" | "custom"
  const [picked, setPicked] = useStateD([currentSeries]);

  const togglePick = s => setPicked(prev => prev.includes(s) ? prev.filter(x => x !== s) : [...prev, s]);

  const handleConfirm = () => {
    if (mode === "all") onConfirm(applicableSeries);
    else if (mode === "current") onConfirm([currentSeries]);
    else onConfirm(picked);
  };

  const totalPrice = (mode === "all" ? applicableSeries : mode === "current" ? [currentSeries] : picked)
    .reduce((s, sn) => s + (item.priceBySeries[sn] || 0), 0);

  // Detecta segmento coberto pela coleção
  const FUND1 = ["1º ano","2º ano","3º ano","4º ano","5º ano"];
  const FUND2 = ["6º ano","7º ano","8º ano","9º ano"];
  const EM = ["1º EM","2º EM","3º EM"];
  const setEq = (a, b) => a.length === b.length && a.every(x => b.includes(x));
  const segmentLabel = setEq(applicableSeries, FUND1) ? "Fundamental I"
    : setEq(applicableSeries, FUND2) ? "Fundamental II"
    : setEq(applicableSeries, EM) ? "Ensino Médio"
    : null;
  const allLabel = segmentLabel
    ? `Adotar em todo o ${segmentLabel} (${applicableSeries.length} séries)`
    : `Adotar nas ${applicableSeries.length} séries da coleção`;

  return (
    <div style={{
      position: "fixed", inset: 0, background: "rgba(20,30,32,0.55)",
      display: "flex", alignItems: "center", justifyContent: "center",
      zIndex: 1000, padding: 20,
    }} onClick={onCancel}>
      <div onClick={e => e.stopPropagation()} style={{
        background: "#fff", borderRadius: 18, padding: 28,
        maxWidth: 540, width: "100%", boxShadow: "0 20px 60px rgba(0,0,0,.3)",
      }}>
        <div style={{ display: "flex", gap: 10, alignItems: "center", marginBottom: 4 }}>
          <span style={{
            padding: "3px 8px", borderRadius: 5, fontSize: 11, fontWeight: 800,
            background: LANG_COLOR[item.lang], color: "#fff",
          }}>{LANG_SHORT[item.lang]}</span>
          <span style={{ fontSize: 12, color: "var(--text-mute)", fontWeight: 600 }}>
            {SUBJ_ICON[item.subject]} {SUBJ_LABEL[item.subject]}
          </span>
        </div>
        <div style={{ fontSize: 20, fontWeight: 800, color: "var(--text)", letterSpacing: -0.4 }}>{item.title}</div>
        <div style={{ fontSize: 13, color: "var(--text-mute)", marginTop: 4 }}>
          {item.publisher} · {segmentLabel ? `coleção do ${segmentLabel}` : `coleção cobre ${applicableSeries.length} séries`} ({applicableSeries[0]} → {applicableSeries[applicableSeries.length - 1]})
        </div>

        <div style={{ marginTop: 22, display: "flex", flexDirection: "column", gap: 8 }}>
          {[
            { id: "all", label: allLabel, sub: "cada série recebe o volume correto" },
            { id: "current", label: `Só em ${currentSeries}`, sub: "adicionar apenas nesta série" },
            { id: "custom", label: "Escolher séries específicas", sub: "selecionar manualmente quais séries" },
          ].map(opt => (
            <label key={opt.id} style={{
              display: "flex", gap: 10, alignItems: "flex-start",
              padding: 12, borderRadius: 10,
              border: mode === opt.id ? "1.5px solid var(--teal-dark)" : "1px solid var(--border)",
              background: mode === opt.id ? "#e7f4f5" : "#fff",
              cursor: "pointer",
            }}>
              <input type="radio" checked={mode === opt.id} onChange={() => setMode(opt.id)} style={{ marginTop: 2, accentColor: "var(--teal-dark)" }}/>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13.5, fontWeight: 700, color: "var(--text)" }}>{opt.label}</div>
                <div style={{ fontSize: 11.5, color: "var(--text-mute)", marginTop: 2 }}>{opt.sub}</div>
              </div>
            </label>
          ))}
        </div>

        {mode === "custom" && (
          <div style={{ marginTop: 14, padding: 12, background: "var(--bg-light)", borderRadius: 8 }}>
            <div style={{ fontSize: 11, color: "var(--text-mute)", fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.6, marginBottom: 8 }}>Séries cobertas pela coleção</div>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
              {applicableSeries.map(s => {
                const on = picked.includes(s);
                return (
                  <button key={s} onClick={() => togglePick(s)} style={{
                    padding: "6px 10px", borderRadius: 5, fontSize: 12, fontWeight: 700,
                    border: on ? "1.5px solid var(--teal-dark)" : "1px solid var(--border)",
                    background: on ? "var(--teal-dark)" : "#fff",
                    color: on ? "#fff" : "var(--text-mute)",
                    cursor: "pointer",
                  }}>{s}</button>
                );
              })}
            </div>
          </div>
        )}

        <div style={{ marginTop: 18, padding: "12px 14px", background: "#e7f4f5", borderRadius: 8, display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
          <span style={{ fontSize: 12, color: "var(--text-mute)", fontWeight: 600 }}>Total estimado</span>
          <span style={{ fontSize: 20, fontWeight: 800, color: "var(--teal-dark)", letterSpacing: -0.5 }}>R$ {totalPrice.toFixed(2)}</span>
        </div>

        <div style={{ marginTop: 18, display: "flex", justifyContent: "flex-end", gap: 8 }}>
          <button onClick={onCancel} style={{
            padding: "10px 16px", background: "transparent", color: "var(--text-mute)",
            border: "1px solid var(--border)", borderRadius: 8, fontSize: 13, fontWeight: 600,
            cursor: "pointer",
          }}>Cancelar</button>
          <button onClick={handleConfirm}
            disabled={mode === "custom" && picked.length === 0}
            style={{
              padding: "10px 18px", background: "var(--teal-dark)", color: "#fff",
              border: "none", borderRadius: 8, fontSize: 13, fontWeight: 700,
              cursor: "pointer",
              opacity: (mode === "custom" && picked.length === 0) ? 0.5 : 1,
            }}>Adotar</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { StepDidaticos, StepDidaticosConfig, StepDidaticosBuilder });
