"""
Project Together — powered by AI: PASSO 1 — Iniciar o projeto (5W2H).

O QUE ESTE PASSO FAZ
  Iniciar um projeto e AUTORIZA-LO: dizer, num documento so, por que ele existe, o
  que ele entrega, quem esta envolvido, onde acontece, quando, COMO sera conduzido
  e quanto custa. O Guia PMBOK 8 chama esse documento de TERMO DE ABERTURA — e diz
  que, numa abordagem adaptativa, ele fica mais enxuto (uma "declaracao concisa de
  visao"), mas responde AS MESMAS PERGUNTAS. Por isso este script e igual nas duas
  abordagens: muda a forma da resposta, nao a pergunta.

RODE ESTE SCRIPT DUAS VEZES — o quadro e montado em DUAS RODADAS, junto com a sua
leitura do artigo. (RODADA, nao "etapa": no PMBOK 8 Together, que roda este mesmo
script, cada um dos 40 e um PROCESSO do Guia — duas rodadas do mesmo processo nao
sao dois processos.)

  RODADA 1 (agora, antes de escolher a abordagem)
    Abre o seu quadro com as 7 perguntas do 5W2H em cartoes. Voce le o artigo e vai
    respondendo: 1.1 justificativa, 1.2 objetivos (OKR), 2.1 e 2.2 o que, 3 quem.
    Da fronteira para baixo, tudo nasce TRANCADO: o bloco 4 (o COMO — e o ONDE, que e
    parte dele) e os cartoes 5 (QUANDO) e 6 (QUANTO).

  --> entre as duas: 01a_escolher_abordagem.py (o COMO: 5 perguntas, voce decide)

  RODADA 2 (rode este script de novo)
    Destranca o COMO, o ONDE, o QUANDO e o QUANTO, escreve o seu termo de abertura e
    monta o RESTO do quadro na forma da sua abordagem (EAP ou Product Backlog...).

  Por que nao montar tudo de uma vez? Por duas razoes, e as duas sao a mesma ordem:
    - a abordagem se ESCOLHE a partir dos fatores da ENTREGA, do PROJETO e da
      ORGANIZACAO (Guia PMBOK 8, secao 4.3) — ou seja, depois de responder por que, o
      que e quem. Escolher antes seria chute;
    - o quando, o quanto e o onde se CALCULAM a partir da abordagem. "Quando fica
      pronto?" e uma pergunta diferente se a resposta e um marco de entrega ou o fim de
      uma Sprint. Perguntar antes e pedir um numero sem saber o que ele significa.

A ORDEM (e a regra de ouro)
  1. VOCE escreve a JUSTIFICATIVA (a unica coisa que a IA nao pode fazer por voce).
  2. A IA propoe, elo por elo, em cima do que voce escreveu — na ordem do proprio termo
     de abertura (1 por que · 2 o que · 3 quem · 4 como · 5 quando · 6 quanto):
       prompt 1: "com base nesta justificativa, quais objetivos voce recomenda?"
       prompt 2: "com base nestes objetivos, quais entregas voce recomenda?"
       prompt 3: "com base nestas entregas, quem sao as partes interessadas?"
       prompt 4: "COMO — qual abordagem?" -> a DECISAO e sua (script 01a). A FRONTEIRA.
       prompt 5: "restricoes, premissas, riscos iniciais e o ONDE" (ja na sua abordagem)
       prompt 6: "quando e quanto (preliminar)" (ja na sua abordagem)
  3. VOCE revisa, corrige e roda. A IA propoe, voce decide.

O QUE ELE FAZ NO SEU QUADRO (idempotente — seguro re-rodar quantas vezes quiser)
  - monta as listas da rodada (quadro.py);
  - escreve os cartoes do Termo de Abertura (as 7 perguntas do 5W2H);
  - le o que VOCE ja respondeu (no modo CHAT, direto do quadro) e nunca sobrescreve;
  - cria as partes interessadas na lista QUEM, agrupadas em Clientes / Equipe /
    Demais (como subtarefas dos 3 cartoes de grupo);
  - transforma os Key Results num checklist do cartao do OKR;
  - guarda tudo em _saida/contexto.md e ja gera o prompt do passo 2.

Pre-requisitos: PROJECTADM_TOKEN e BOARD_ID no .env (o Iniciar ja fez isso).
O nome do projeto ele pergunta; a ABORDAGEM vem do 01a.
Execute: Ctrl+F5.
"""
import os
import re
from datetime import date as _date

from env import cfg, require, save_cfg
from pa_client import (create_card, update_card, sincronizar_checklists,  # noqa: F401
                       garantir_checklist, list_cards)
from runner import header, ok, step, warn, done, copiar
import artefatos
import contexto
import entradas
import progresso
import prompts
import team_check
from quadro import (garantir_listas, garantir_termo, garantir_guias, garantir_referencia,
                    cards_do_termo_ids, abordagem_do_env, abordagem_do_quadro,
                    distribuir_caixa_entrada, ler_inputs, respostas_do_termo,
                    texto_das_entregas, texto_dos_requisitos,
                    parte_ja_existe, parecidas_com)
from idioma import T, Tf

# ─────────────────────────────────────────────────────────────────────────────
# ESTE SCRIPT SERVE AOS DOIS CURSOS — e eles nao falam a mesma lingua
#
#   Project Together   este e' o PASSO 1 de 10 ("Iniciar o projeto (5W2H)")
#   PMBOK 8 Together   este e' o PROCESSO 1 de 40 ("Iniciar projeto ou fase") — e
#                      tambem o PROCESSO 2 ("Identificar as partes interessadas")
#
# Quem chamou o script diz quem e' (catalogo_pmbok8.curriculo_corrente / unidade_corrente,
# declarados pelo processo.py e herdados pelo subprocesso). Estas tres funcoes sao o unico
# lugar onde essa diferenca vira texto — nenhuma tela abaixo escreve "Passo 1" a mao.
# ─────────────────────────────────────────────────────────────────────────────
def _cat():
    """O catalogo, ou None. Sem ele o curso fala como o Project Together — degrada,
    nunca quebra: um pacote sem o catalogo continua rodando o passo do aluno."""
    try:
        import catalogo_pmbok8 as cat
        return cat
    except Exception:
        return None


def _rotulo_desta_execucao():
    """"Passo 1" ou "Processo 2" — de quem e' esta execucao."""
    cat = _cat()
    if not cat:
        return T("Passo 1")
    cur = cat.curriculo_corrente()
    n = (cat.unidade_corrente() or 1) if cur == cat.CURRICULO_40 else 1
    return cat.rotulo_unidade(n, cur)


def _titulo_desta_execucao():
    """O cabecalho: "Passo 1 — Iniciar o projeto (5W2H)" ou "Processo 2 — Identificar
    as partes interessadas"."""
    cat = _cat()
    if not cat or cat.curriculo_corrente() == cat.CURRICULO_10:
        return T("Passo 1 — Iniciar o projeto (5W2H)")
    n = cat.unidade_corrente() or 1
    return f"{cat.rotulo_unidade(n)} — {cat.nome_unidade(n)}"


def _referencia_engajamento():
    """Onde a estrategia de engajamento e' definida: "passo 6" la', "Processo 24" aqui.

    Pelo SCRIPT, nao pela saida: no curso de 40, quem gera o Registro das Partes e' o
    Processo 2 (identificar), e a estrategia de engajamento so' nasce no 24 (gerenciar o
    engajamento). Apontar pela saida mandaria o aluno de volta ao processo em que ele ja
    esta.
    """
    cat = _cat()
    if not cat:
        return T("passo 6")
    if cat.curriculo_corrente() == cat.CURRICULO_10:
        return T("passo 6")
    return cat.rotulo_do_script(6, "06_engajar_partes.py")


def _e_o_processo_das_partes():
    """True quando quem chamou foi o PROCESSO 2 do PMBOK 8 Together.

    E' o unico ponto do script em que o curso de 40 pede uma coisa DIFERENTE do de 10 —
    e o motivo esta no proprio Guia: o Termo de Abertura e' ENTRADA de "Identificar as
    partes interessadas" (2.5.2.1). Nao sao duas perguntas concorrentes, sao duas
    altitudes da mesma informacao. Por isso o Processo 2 nao repete a pergunta do Termo:
    ele pergunta QUEM FALTA (prompts.py, chave "partes_completar").
    """
    cat = _cat()
    return bool(cat and cat.curriculo_corrente() == cat.CURRICULO_40
                and cat.unidade_corrente() == 2)


# ─────────────────────────────────────────────────────────────────────────────
# >>> VALORES INICIAIS (o curso le tudo do QUADRO; isto e' so o ponto de partida)
#
#  1) JUSTIFICATIVA — VOCE escreve. 3 a 6 frases: qual e a dor hoje, quem sofre
#     com ela, o que acontece se nada for feito, o que muda quando o projeto
#     entregar. Travou? Rode o prompt "destravar a justificativa" (card 01 da
#     lista Referencias) — a IA te faz perguntas, mas o texto continua seu.
JUSTIFICATIVA = T("""
Escreva aqui, com as suas palavras, por que este projeto existe.
""")

#  2) OKR — do prompt 1 ("com base nesta justificativa, quais objetivos voce
#     recomenda?"). Cada objetivo diz ONDE chegar; os Key Results provam que chegou.
#     Quantos objetivos o projeto pedir — e de 2 a 5 Key Results em CADA objetivo.
OBJETIVOS = [
    # {"objetivo": "", "key_results": [
    #     {"kr": "", "meta": ""},   # KR = so' resultado + meta (quem/quando vao nas entregas e tarefas)
    # ]},
]

#  3) ENTREGAS — do prompt 2 ("com base nestes objetivos, quais entregas voce
#     recomenda?"). Um resultado (substantivo), nao uma atividade.
ENTREGAS = [
    # {"nome": "", "kr": "", "requisito": "", "aceitacao": ""},
]

#  4) PARTES — do prompt 3 ("com base nestas entregas, quem sao as partes
#     interessadas?"). grupo = cliente | equipe | demais.
PARTES = [
    # {"nome": "", "grupo": "cliente", "papel": "", "espera": "",
    #  "poder": "alto", "interesse": "alto"},
]

#  5) ONDE / QUANDO / QUANTO — do prompt 4 (preliminares; o detalhe vem no passo 4).
ONDE = ""
MARCOS = [
    # {"marco": "", "quando": "Semana 4"},
]
ORDEM_DE_GRANDEZA = ""

#  6) O resto do COMO — do prompt 5. Nivel de ABERTURA (o detalhe vem nos passos 2 a 4).
RESTRICOES = [
    # "Orcamento maximo de R$ 30 mil, aprovado para 2026",
]
PREMISSAS = [
    # "A equipe estara disponivel a partir de julho",
]
RISCOS_INICIAIS = [
    # {"risco": "", "probabilidade": "media", "impacto": "alto", "resposta": ""},
]

# <<< FIM DOS VALORES INICIAIS
# ─────────────────────────────────────────────────────────────────────────────

# O .env sai do course.json com o texto-guia NO IDIOMA do aluno, entao as DUAS formas contam.
# Se so a portuguesa estivesse aqui, o pacote EN leria "WRITE YOUR PROJECT NAME HERE" como se
# fosse um nome de verdade, nunca perguntaria, e batizaria o quadro com o texto-guia — foi
# exatamente o que aconteceu em 02/08/2026. Fonte dos textos: course.json (env_pt / env_en).
_PLACEHOLDER_PROJETO = ("",
                        "ESCREVA O NOME DO SEU PROJETO AQUI",   # PT
                        "WRITE YOUR PROJECT NAME HERE")         # EN

# As primeiras palavras do texto-guia da JUSTIFICATIVA, no idioma do pacote:
# "escreva aqui" (PT) · "write here" (EN). Mesma armadilha do _PLACEHOLDER_PROJETO
# acima, e a mesma correcao — derivada da constante, que ja' vem traduzida.
#
# Ate 04/08/2026 este teste era `startswith("escreva aqui")`, o prefixo PORTUGUES
# escrito a mao. No pacote EN a constante e' "Write here, in your own words, why this
# project exists.": o teste dava False, o texto-guia passava por justificativa do aluno
# e o Passo 1 o GRAVAVA no cartao 1.1 — dai em diante o curso pulava direto para o
# prompt do OKR sem nunca ter pedido a justificativa, e o painel dizia
# "[OK] 1.1 Justificativa" para quem nao escreveu nenhuma (Eduardo, 04/08/2026, FIRE).
_ABERTURA_JUSTIFICATIVA = " ".join(JUSTIFICATIVA.split()[:2]).lower()


def nome_do_projeto(c):
    """O nome do projeto — perguntado aqui, nao editado no .env.

    No modo CHAT o aluno nunca abre um arquivo do curso; pedir para ele "editar o
    .env" era a ultima peca que quebrava essa promessa. O quadro E o projeto: ele
    passa a se chamar assim (quadro.garantir_nome_do_quadro).
    """
    nome = (c.get("PROJECT") or "").strip()
    if nome not in _PLACEHOLDER_PROJETO:
        return nome
    print(T("Antes de tudo: como se chama o seu projeto?"))
    print(T("(pode ser simples e pessoal — 'Melhorar minha qualidade de vida', 'PMO da"))
    print(T(" Horizonte'. Dá para mudar depois: é só rodar este passo de novo.)\n"))
    while True:
        try:
            nome = input(T("   Nome do seu projeto: ")).strip()
        except (EOFError, KeyboardInterrupt):
            raise SystemExit(T("\n(sem nome, sem projeto — rode o Passo 1 quando quiser.)"))
        if len(nome) >= 3:
            save_cfg({"PROJECT": nome})
            ok(Tf('anotado: "{0}" (o seu quadro passa a se chamar assim)', nome))
            return nome
        print(T("   (escreva um nome com pelo menos 3 letras)\n"))


def _normalizar_data(s):
    """'2026-08-03', '03/08/2026' ou '03-08-2026' -> '2026-08-03'. '' se vazio/inválido."""
    s = (s or "").strip()
    m = re.match(r"^(\d{4})[-/.](\d{1,2})[-/.](\d{1,2})$", s)
    if m:
        y, mo, d = m.groups()
    else:
        m = re.match(r"^(\d{1,2})[-/.](\d{1,2})[-/.](\d{4})$", s)
        if not m:
            return ""
        d, mo, y = m.groups()
    try:
        return _date(int(y), int(mo), int(d)).isoformat()
    except ValueError:
        return ""


def data_inicio_do_projeto(c):
    """Quando o projeto COMEÇA — perguntado JUNTO com o nome, aqui no Passo 1. É a
    âncora do cronograma (Passo 4): sem ela, a IA não consegue calcular as datas e fica
    pedindo. Fica no cartão 5 (QUANDO) do termo de abertura e alimenta o Passo 4 — a IA
    não precisa mais pedir.

    Só salva quando você informa uma data válida. Em branco é resposta legítima
    ('decido depois'), mas como é a âncora do cronograma o Passo 1 VOLTA A PERGUNTAR nas
    próximas rodadas até você informá-la (não fica marcada como 'adiada' para sempre)."""
    ja = _normalizar_data(c.get("START_DATE"))
    if ja:
        return ja
    print(T("\nE quando você pretende COMEÇAR o projeto?"))
    print(T("(é a âncora do seu cronograma — no formato AAAA-MM-DD, ex.: 2026-08-03."))
    print(T(" Ainda não sabe? Dê Enter — eu pergunto de novo na próxima vez que rodar.)\n"))
    while True:
        try:
            resp = input(T("   Data de início (AAAA-MM-DD, ou Enter): ")).strip()
        except (EOFError, KeyboardInterrupt):
            return ""
        if not resp:
            print(T("   (sem problema — eu pergunto de novo quando você rodar o Passo 1.)"))
            return ""
        d = _normalizar_data(resp)
        if d:
            save_cfg({"START_DATE": d})
            ok(Tf("anotado: início em {0} (é a âncora do seu cronograma no Passo 4)", d))
            return d
        print(T("   (use o formato AAAA-MM-DD, ex.: 2026-08-03; ou Enter para decidir depois)\n"))


def gerente_do_projeto(c):
    """Quem é o GERENTE do projeto — você. Perguntado JUNTO com o nome e a data, aqui no
    Passo 1. Aparece no Kick-Off do Projeto (o .pptx que o Passo 7 gera), no lugar de
    "gerente do projeto". O ProjectAdm não expõe esse nome pela API, então é você quem o
    informa — uma vez.

    Em branco é resposta legítima ('depois') e, como não trava nada no curso, NÃO fica
    reperguntando: o Kick-Off deixa um lembrete no lugar até você informar. Rerode o
    Passo 1 quando quiser preencher."""
    ja = (c.get("MANAGER") or "").strip()
    if ja and not ja.upper().startswith("ESCREVA"):
        return ja
    print(T("\nE quem é o GERENTE deste projeto (provavelmente você)?"))
    print(T("(aparece no Kick-Off do Projeto que o curso gera no Passo 7. Enter para deixar em branco.)\n"))
    try:
        resp = input(T("   Nome do gerente do projeto (ou Enter): ")).strip()
    except (EOFError, KeyboardInterrupt):
        return ""
    if resp:
        save_cfg({"MANAGER": resp})
        ok(Tf("anotado: gerente do projeto = {0}", resp))
        return resp
    print(T("   (sem problema — o Kick-Off deixa um lembrete até você informar.)"))
    return ""


c = cfg()
require(c, "PROJECTADM_TOKEN", "BOARD_ID")
abordagem = abordagem_do_env()
# A FONTE DA VERDADE E O QUADRO: se o aluno nao rodou o 01a mas ESCREVEU a abordagem
# no cartao 4.1 (ex.: "PREDITIVA"), o curso honra essa decisao e destranca o COMO.
# Antes, so o .env valia — quem escrevia no cartao ficava preso na rodada 1 (o "python
# nao reconheceu a abordagem" do Eduardo, board 270).
#
# RODADA, NAO "ETAPA" (Eduardo, 14/08/2026): este script roda DUAS VEZES — antes e depois
# da escolha da abordagem. Chamar isso de "etapa" colidia de frente com o PMBOK 8
# Together, onde ETAPA ja nao existe e cada um dos 40 e um PROCESSO do Guia. Duas rodadas
# do mesmo passo/processo nao sao dois passos/processos.
abordagem_via_cartao = False
if not abordagem:
    detectada = abordagem_do_quadro(c)
    if detectada:
        abordagem = detectada
        abordagem_via_cartao = True
        save_cfg({"APPROACH": abordagem})
rodada = 2 if abordagem else 1

header(_titulo_desta_execucao()
       + (Tf(" · rodada {0} de 2", rodada) if rodada == 1 else ""))
projeto = nome_do_projeto(c)
data_inicio = data_inicio_do_projeto(c)   # perguntada junto com o nome; âncora do Passo 4
gerente = gerente_do_projeto(c)           # opcional; aparece no Kick-Off do Projeto (Passo 7)

justificativa = JUSTIFICATIVA.strip()
if justificativa.lower().startswith(_ABERTURA_JUSTIFICATIVA):
    justificativa = ""

if rodada == 1:
    print(T("\nRODADA 1 — abrindo o seu quadro com as 7 perguntas do 5W2H."))
    print(Tf("Você responde cada cartão conforme lê o artigo do {0}. O bloco COMO",
             _rotulo_desta_execucao()))
    print(T("(cartões 4.x) fica trancado até você escolher a abordagem — é ela que"))
    print(T("define a forma do resto do quadro.\n"))
else:
    print(Tf('\nRODADA 2 — abordagem de desenvolvimento: {0}.',
             prompts.nome_abordagem(abordagem)))
    if abordagem_via_cartao:
        ok(Tf("li a abordagem {0} que você escreveu no cartão 4.1 do quadro.",
              prompts.nome_abordagem(abordagem)))
        print(T("  (Quer registrar o PORQUÊ — os 5 eixos do Guia PMBOK 8? Rode"))
        print(T("   01a_escolher_abordagem.py quando quiser; não é obrigatório.)"))
    print(T("As perguntas do 5W2H são as mesmas nas duas abordagens (Guia PMBOK 8);"))
    print(T("o que muda é a forma e o detalhe da resposta.\n"))

# 1) O quadro (rodada 1: as 3 listas do 5W2H · rodada 2: o quadro completo)
step(T("Montando as listas do seu quadro..."))
ids = garantir_listas(abordagem, log=step)
step(T("Termo de Abertura (as 7 perguntas):"))
garantir_termo(ids, abordagem, log=step)
step(T("Guia das demais listas:"))
garantir_guias(ids, abordagem, log=step)
# O playbook (lista Referencias) e escrito DEPOIS de ler o quadro — la embaixo. E que
# o prompt de cada elo entra no cartao JA PREENCHIDO com o que voce respondeu, e para
# isso e' preciso ter lido as suas respostas antes.

# 2) DE ONDE VEM A SUA RESPOSTA
#    Do QUADRO, sempre. A IA devolveu texto, voce colou na Caixa de entrada (ou
#    direto nos cartoes) da lista INPUTS — e o script le de la. Voce nunca abre um .py.
if True:
    step(T("Lendo as suas respostas do QUADRO (lista INPUTS):"))
    distribuir_caixa_entrada(ids, log=step)
    _in = ler_inputs(ids)
    justificativa = (_in.get("justificativa") or justificativa).strip()
    if _in.get("okr"):
        OBJETIVOS = entradas.objetivos_do_okr(_in["okr"])
    ENTREGAS = _in.get("entregas") or ENTREGAS
    PARTES = _in.get("partes") or PARTES
    ONDE = _in.get("onde") or ONDE
    MARCOS = _in.get("marcos") or MARCOS
    ORDEM_DE_GRANDEZA = _in.get("ordem_de_grandeza") or ORDEM_DE_GRANDEZA
    RESTRICOES = _in.get("restricoes") or RESTRICOES
    PREMISSAS = _in.get("premissas") or PREMISSAS
    RISCOS_INICIAIS = _in.get("riscos_iniciais") or RISCOS_INICIAIS
    ok(Tf("li do quadro: {0} entrega(s), {1} parte(s), {2} risco(s) inicial(is).", len(ENTREGAS), len(PARTES), len(RISCOS_INICIAIS)))

# 3) A MEMORIA do projeto (o playbook vem depois — ver escrever_playbook).
dados = contexto.salvar(
    projeto=projeto, abordagem=abordagem, justificativa=justificativa,
    okr={"objetivos": OBJETIVOS} if OBJETIVOS else None,
    entregas=ENTREGAS, partes=PARTES, onde=ONDE, marcos=MARCOS,
    ordem_de_grandeza=ORDEM_DE_GRANDEZA, restricoes=RESTRICOES, premissas=PREMISSAS,
    riscos_iniciais=RISCOS_INICIAIS)


def escrever_playbook():
    """O playbook do curso na lista Referencias — e os 6 prompts da corrente, resolvidos
    CONTRA O QUADRO: cada [INPUT x] vira o texto do cartao x que voce respondeu. Uma
    leitura so' serve os tres destinos: o cartao do elo, o arquivo em _saida/ e a sua
    area de transferencia. Devolve `resolvidos` (o que o proximo elo usa).

    RODA DEPOIS DE GRAVAR OS CARTOES desta rodada — nunca antes. O script le o quadro e
    SO' DEPOIS escreve nele; um playbook montado com a foto anterior nasce dizendo
    "(ainda em branco no meu quadro: 4.1 — a abordagem...)" sobre um cartao que este
    mesmo passo preencheu segundos antes, e o curso acaba pedindo ao aluno uma resposta
    que ele ja deu (Eduardo, 2026-07-24: "no quadro ja esta escrito que e' agil").
    Copiar o texto de um cartao para dentro de um prompt seria trabalho operacional —
    a informacao ja esta no quadro, e quem le o quadro e este script.
    """
    resolvidos = contexto.prompts_da_corrente(ids)
    step(T("Playbook do curso na lista Referências (com os seus prompts já preenchidos):"))
    garantir_referencia(ids, abordagem, log=step, resolvidos=resolvidos)
    contexto.gerar_correntes_p1(ids, resolvidos)
    return resolvidos


# 4) As suas respostas nos cartoes do termo (o que o script deriva/organiza)
cards = cards_do_termo_ids(ids)


def _escrever(titulo_contem, texto):
    """Grava a sua resposta no cartao do termo cujo titulo comeca com o prefixo."""
    if not texto:
        return False
    cid = next((cid for t, cid in cards.items() if t.startswith(titulo_contem)), None)
    if not cid:
        warn(Tf("cartao do termo nao encontrado: {0}", titulo_contem))
        return False
    update_card(cid, descricao=texto)
    ok(Tf("{0} — preenchido", titulo_contem))
    return True


if not justificativa:
    # NAO e erro: na rodada 1 esta e exatamente a situacao esperada — o quadro acabou
    # de nascer e o aluno vai escrever a justificativa lendo o artigo.
    # Este e' o unico caminho que SAI do passo sem gravar cartao nenhum — entao o
    # playbook e escrito aqui, antes de sair: mesmo quem ainda nao escreveu a
    # justificativa tem de achar o playbook (e o prompt para destravá-la) no quadro.
    escrever_playbook()
    print()
    done(T("O seu quadro está pronto para receber as suas respostas."))
    print(T("  Abra o quadro no ProjectAdm: a lista INPUTS (Projeto 5W2H) tem uma pergunta"))
    print(T("  por cartão. Comece pelo cartão 1.1 — a JUSTIFICATIVA.\n"))
    print(T("  É o único texto do curso que a IA NÃO escreve por você: é a sua dor, o seu"))
    print(T("  contexto, a sua voz. 3 a 6 frases bastam. (Travou? Cartão 90 da lista"))
    print(T("  Referências: a IA te faz perguntas — o texto continua seu.)\n"))
    print(T("  Escreveu? Rode o Passo 1 de novo — ele lê o quadro e segue com você."))
    raise SystemExit(0)

_escrever("1.1", justificativa)

if OBJETIVOS:
    # Um projeto raramente tem um objetivo so. Numeramos KR 1.1, KR 1.2, KR 2.1... —
    # e e por esse numero que as entregas (2.1) dizem a qual KR elas servem.
    linhas = []
    for i, o in enumerate(OBJETIVOS, 1):
        n = f" {i}" if len(OBJETIVOS) > 1 else ""
        linhas.append(Tf("OBJETIVO{0}: {1}", n, o.get('objetivo', '')).strip())
        for j, kr in enumerate(o.get("key_results") or [], 1):
            # KR = só resultado + meta. Quem faz e quando vivem nas entregas e nas tarefas.
            #
            # A META PROVISÓRIA TEM DE SOBREVIVER AO WRITE-BACK (Eduardo, quadro 341, 20/08/2026)
            #     O prompt manda a IA escrever 'meta provisória:' quando o número é estimativa,
            #     o parser detecta (`meta_provisoria`), o `artefatos.py` carimba
            #     " (meta provisória)" nos documentos e o `verificar_okrs.py` conta. Só que
            #     AQUI o cartão era reescrito sempre com 'meta:' — e o cartão é o armazém.
            #     Resultado: na primeira gravação a estimativa virava meta firme, e como o
            #     passo relê o cartão nas vezes seguintes, a marca sumia para sempre — junto
            #     com o único aviso de que aquele número era um chute. Foi assim que os 3 KRs
            #     provisórios do quadro 341 (1000 contatos, 100/mês, 1 venda/mês) viraram
            #     alvos firmes na primeira rodada do Passo 1.
            #     Os dois literais ficam à vista de propósito: `extrair_textos.py` só enxerga
            #     o texto escrito dentro do Tf(), nunca uma variável.
            if kr.get("meta_provisoria"):
                linhas.append(Tf("KR {0}.{1}: {2} — meta provisória: {3}",
                                 i, j, kr.get('kr', ''), kr.get('meta', '')))
            else:
                linhas.append(Tf("KR {0}.{1}: {2} — meta: {3}",
                                 i, j, kr.get('kr', ''), kr.get('meta', '')))
        linhas.append("")
    _escrever("1.2", "\n".join(linhas).strip())

    # Os KRs viram checklist (um por objetivo): da para marcar cada um quando for
    # atingido. Upsert — o script e rodado varias vezes e o item marcado e do aluno.
    #
    # SINCRONIZAR, nao so' garantir (Eduardo, quadro 326, 2026-08-08): o titulo do
    # checklist carrega o TEXTO do objetivo, entao reescrever o OKR — que o curso manda
    # fazer — criava um checklist novo e deixava o antigo no cartao. Depois de tres
    # revisoes havia 9 checklists e 29 itens, com DOIS "Objetivo 1" se contradizendo.
    cid = next((cid for t, cid in cards.items() if t.startswith("1.2")), None)
    if cid:
        # O TITULO NAO LEVA O TEXTO DO OBJETIVO (Eduardo, 2026-08-08). Era
        # "Objetivo 1 — Consolidar uma base de renda passiva": reescrever o objetivo
        # mudava o titulo, e como a API nao tem PUT /checklists o curso tinha de criar um
        # novo e apagar o velho — e o DELETE de checklist e' soft no servidor, deixando
        # uma linha vazia na tela que a API nem enxerga mais. Com "Objetivo 1" o titulo
        # nunca muda: reescrever o OKR so' sincroniza os ITENS (esses apagam de verdade).
        # O texto do objetivo continua no CORPO do cartao 1.2, que e' onde ele se le'.
        esperados = []
        for i, o in enumerate(OBJETIVOS, 1):
            krs = o.get("key_results") or []
            if not krs:
                continue
            titulo = T("Key Results") if len(OBJETIVOS) == 1 else Tf("Objetivo {0}", i)
            esperados.append((titulo, [
                Tf("KR {0}.{1}: {2} (meta: {3})", i, j, kr.get('kr', ''),
                   kr.get('meta', ''))
                for j, kr in enumerate(krs, 1)]))
        r = {"itens_novos": 0, "itens_apagados": 0, "chk_apagados": 0, "mantidos": []}
        try:
            r = sincronizar_checklists(cid, esperados)
        except Exception as e:
            warn(Tf("não consegui montar os checklists do cartão 1.2: {0}", e))
        krs_total = sum(len(o.get("key_results") or []) for o in OBJETIVOS)
        ok(Tf("{0} objetivo(s) e {1} Key Result(s) no cartão 1.2{2}",
              len(OBJETIVOS), krs_total,
              Tf(" ({0} novo(s) no checklist)", r["itens_novos"])
              if r["itens_novos"] else ""))
        if r["itens_apagados"] or r["chk_apagados"]:
            ok(Tf("limpeza do OKR anterior no cartão 1.2: {0} item(ns) e {1} "
                  "checklist(s) removido(s).", r["itens_apagados"], r["chk_apagados"]))
        # O que o aluno marcou nao se apaga sozinho: ele decide.
        for titulo in r["mantidos"]:
            warn(Tf('"{0}" saiu do OKR, mas está marcado — deixei no cartão 1.2. '
                    'Apague você, se já não valer.', titulo))

if ENTREGAS:
    # O REQUISITO E A ACEITACAO moram no cartao 2.2. Na 1a rodada eles vem no bloco
    # [2.1] da IA (junto das entregas); dali em diante o cartao 2.1 e reescrito so' com
    # nome + KR, entao a fonte deles passa a ser o 2.2. Preserva os dois: se a entrega
    # nao trouxer requisito do 2.1, busca no 2.2 pelo nome. Sem isto, o requisito sumia
    # na 2a rodada e o cartao 2.2 ficava vazio (Eduardo, board 270, 2026-07-18).
    if True:
        _req22 = {e2.get("nome", ""): e2
                  for e2 in entradas.entregas(respostas_do_termo(ids).get("2.2", ""))}
        for e in ENTREGAS:
            if not (e.get("requisito") or e.get("aceitacao")):
                src = _req22.get(e.get("nome", ""))
                if src:
                    e["requisito"] = src.get("requisito", "")
                    e["aceitacao"] = src.get("aceitacao", "")
    # Cartao 2.1 = entregas + KR, no MESMO formato que o parser le de volta (campo
    # "serve ao KR:", nao "(serve ao ...)" entre parenteses). Assim re-rodar o Passo 1
    # e' idempotente: le limpo, escreve limpo — e um cartao 2.1 antigo com lixo se
    # auto-cura (entradas.entregas limpa na leitura).
    # O FORMATO mora no quadro.py: e' o mesmo texto que a ENGENHARIA REVERSA grava quando
    # reconstroi estes dois cartoes a partir da EAP. Dois escritores, um formato.
    _escrever("2.1", texto_das_entregas(ENTREGAS))
    _escrever("2.2", texto_dos_requisitos(ENTREGAS))

# Da fronteira para baixo (bloco COMO + ONDE + QUANDO + QUANTO), so na RODADA 2: na
# rodada 1 esses cartoes estao trancados de proposito. A abordagem ainda nao foi
# escolhida — e e ela que define a FORMA do como, e como se calcula o quando, o quanto
# e o onde. Escrever antes seria dar a resposta antes da pergunta.
if rodada == 2:
    # 4.1 = a decisao da abordagem (a justificativa que o 01a gerou).
    # Se o abordagem.md nao existe (o aluno escreveu ABORDAGEM no .env na mao, ou apagou
    # a pasta _saida), o cartao 4.1 ficaria VAZIO — e como e' ele que marca o elo 4 como
    # respondido, o curso mandaria o aluno rodar o 01a de novo, para sempre. A decisao
    # ja' foi tomada: registramos ao menos qual foi.
    try:
        import os
        md = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                          "_saida", "abordagem.md")
        if os.path.exists(md):
            _escrever("4.1", open(md, encoding="utf-8").read().strip())
        elif "4.1" not in respostas_do_termo(ids):
            _escrever("4.1", Tf("Abordagem de desenvolvimento escolhida: {0}.\n\n"
                                "Quer registrar POR QUÊ (os 5 eixos do Guia PMBOK 8)? "
                                "Rode 01a_escolher_abordagem.py.",
                                prompts.nome_abordagem(abordagem)))
    except Exception:
        pass
    if RESTRICOES:
        _escrever("4.2", "\n".join(f"• {r}" for r in RESTRICOES))
    if PREMISSAS:
        _escrever("4.3", "\n".join(f"• {p}" for p in PREMISSAS) + "\n\n" +
                  T("Premissa que cai vira risco — revise esta lista a cada passo."))
    if RISCOS_INICIAIS:
        _escrever("4.4", "\n".join(
            f"• {r.get('risco','')}\n    "
            + Tf("probabilidade: {0} · impacto: {1}",
                 r.get('probabilidade', ''), r.get('impacto', '')) + "\n    "
            + Tf("resposta: {0}", r.get('resposta', ''))
            for r in RISCOS_INICIAIS))
    if ENTREGAS:
        # 4.5 = a visao inicial do escopo (que o passo 2 abre em EAP ou em backlog).
        _escrever("4.5", "\n".join(f"• {e.get('nome','')}" for e in ENTREGAS) + "\n\n" +
                  (T("No passo 2 cada entrega se abre em pacotes de trabalho (EAP).")
                   if abordagem == "PREDITIVA" else
                   T("No passo 2 cada entrega vira histórias priorizadas no Product "
                     "Backlog.")))
    # 4.6 = o ONDE. E parte do COMO: onde o trabalho acontece depende de como voce vai
    # conduzi-lo. E a menos decisiva das sete perguntas — em branco e uma resposta
    # legitima ("decido no momento certo").
    if ONDE:
        _escrever("4.6", ONDE)
    # 5 = QUANDO. A DATA DE INÍCIO do projeto (perguntada no topo do Passo 1) é a âncora
    # do cronograma e mora AQUI, no termo de abertura — é ela que o Passo 4 usa para
    # calcular as datas, sem a IA ter de pedir. Vai como 1ª linha (sem '•'), então
    # entradas.marcos a ignora e lê só os marcos abaixo. Os marcos vêm depois.
    if MARCOS or data_inicio:
        linhas5 = []
        if data_inicio:
            linhas5.append(Tf("Data de início do projeto: {0}", data_inicio))
            if MARCOS:
                linhas5.append("")
        linhas5 += [f"• {m.get('marco','')} — {m.get('quando','')}" for m in MARCOS]
        _escrever("5.", "\n".join(linhas5).strip())
    if ORDEM_DE_GRANDEZA:
        _escrever("6.", ORDEM_DE_GRANDEZA)

# 3) Partes interessadas: 3 cartoes de grupo + 1 subtarefa por parte
def _titulo_de_cartao(nome):
    """O ProjectAdm recusa titulo com menos de 3 caracteres (HTTP 400).

    E o aluno tem todo o direito de escrever "Eu" como parte interessada — no
    projeto de vida dele, ele E a principal. Entao qualificamos o nome em vez de
    perder a parte interessada."""
    nome = (nome or "").strip()
    return f"{nome} (parte interessada)" if 0 < len(nome) < 3 else nome


if PARTES:
    step(T("Partes interessadas (Clientes / Equipe / Demais)..."))
    grupos = {"cliente": T("CLIENTES — quem recebe o valor"),
              "equipe": T("EQUIPE — quem faz"),
              "demais": T("DEMAIS — quem influencia, aprova ou é impactado")}
    existentes = {(cd.get("titulo") or ""): cd["id"] for cd in list_cards(ids["PARTES"])}
    pais = {}
    for chave, titulo in grupos.items():
        pais[chave] = existentes.get(titulo) or create_card(
            ids["PARTES"], titulo,
            T("Cada parte interessada deste grupo é uma subtarefa deste cartão."))
    for p in PARTES:
        g = (p.get("grupo") or "demais").strip().lower()
        g = g if g in pais else "demais"
        titulo = _titulo_de_cartao(p.get("nome", ""))
        if not titulo or parte_ja_existe(titulo, existentes):
            continue
        parecidas = parecidas_com(titulo, existentes)
        if parecidas:
            # TODAS, nunca so' a primeira: quando duas partes viram uma (no 326,
            # "Parceiros de afiliado" + "Google AdSense" viraram um cartao so'), nomear
            # apenas uma delas deixa a outra orfa no quadro sem ninguem perceber.
            warn(Tf('"{0}" parece ser a mesma parte que {1} — criei assim mesmo. Se for a '
                    "mesma, apague no quadro o(s) cartão(ões) antigo(s) e fique com o que "
                    "tem a conta ligada.",
                    titulo, ", ".join(f'"{t}"' for t in parecidas)))
        # A linha "e-mail:" nasce VAZIA e o aluno preenche — a IA nao tem como saber o
        # endereco de ninguem, e inventar um seria pior do que deixar em branco. Ela
        # existe desde o Passo 1 porque e' a linha que o Passo 7 le para mandar a cada
        # dono a lista de atividades dele, e porque e' a coluna "e-mail" do Registro das
        # partes interessadas (2026-08-07).
        desc = Tf("Papel: {0}\nO que espera do projeto: {1}\n"
                  "Poder: {2} · Interesse: {3}\n"
                  "e-mail: {4}\n\n"
                  "No {5} você define a estratégia de engajamento desta parte.",
                  p.get('papel', ''), p.get('espera', ''),
                  p.get('poder', ''), p.get('interesse', ''),
                  p.get('email', '') or T("(escreva aqui o e-mail desta pessoa)"),
                  _referencia_engajamento())
        from pa_client import api
        try:
            novo = api("POST", "/cartoes", {"lista_id": ids["PARTES"], "titulo": titulo,
                                            "descricao": desc, "cartao_pai_id": pais[g]})
            # entra no indice AGORA: sem isto, duas partes com as mesmas palavras vindas
            # na MESMA rodada viram dois cartoes — o gemeo nasceria dentro do proprio laco
            existentes[titulo] = ((novo or {}).get("dados") or {}).get("id")
            ok(f"[{g}] {titulo}")
        except Exception as e:
            # Uma parte interessada que o ProjectAdm recusou nao pode derrubar o passo
            # inteiro (o termo de abertura ja esta escrito). Avisa e segue.
            warn(Tf('não consegui criar a parte "{0}" ({1}) — crie no quadro à mão.', titulo, e))

# 4b) O QUEM VIRA UMA CONTA: cada membro da EQUIPE ligado ao usuario dele no ProjectAdm.
#     E' o elo que faltava (Eduardo, 07/08/2026). O Passo 4 ja sabia atribuir a tarefa ao
#     usuario que esta no cartao da pessoa, e o Passo 7 manda o e-mail para ele — so' que
#     ninguem nunca punha esse usuario la, entao os dois rodavam a vazio. Aqui, no QUEM,
#     e' o lugar certo: e' onde o aluno esta pensando em gente.
#     Roda SEMPRE (nao so' quando PARTES veio nesta rodada), porque a equipe pode ter
#     entrado numa rodada anterior ou pelo guarda do team_check.
#     E' OPCIONAL desde 18/08/2026: LINK_TEAM_ACCOUNTS no .env (SIM · AUTO · NAO). Quem
#     planeja sozinho, ou desenha um projeto cujo time ainda nao existe, respondia "pular"
#     uma vez por pessoa a cada rodada do Passo 1 — ver team_check.modo_ligacao.
if ids.get("PARTES"):
    try:
        _modo = team_check.modo_ligacao(c)
        if _modo == "NAO":
            step(Tf('não liguei a equipe às contas do ProjectAdm ({0}=NAO no seu .env). '
                    "Cada pessoa segue pelo e-mail escrito no cartão dela.",
                    team_check.CHAVE_LIGACAO))
        _vinc, _ja, _sem = team_check.vincular_usuarios(ids, modo=_modo)
        if _vinc or _ja:
            ok(Tf("{0} pessoa(s) da equipe ligadas à conta do ProjectAdm ({1} já "
                  "estavam). A tarefa de cada uma passa a ser ATRIBUÍDA a ela no quadro, "
                  "e o e-mail do Passo 7 vai para o endereço da conta.", _vinc, _ja))
        if _sem:
            step(Tf("sem conta no ProjectAdm: {0}. Elas seguem pelo e-mail escrito no "
                    'cartão (linha "e-mail:") — é o suficiente para o Passo 7.',
                    ", ".join(_sem)))
        # Dizer ONDE se desliga, e so' para quem esta pagando o preco: quem tem gente sem
        # conta e' quem respondeu ao menu. Quem nao tem nao precisa saber que a chave existe.
        if _sem and _modo == "SIM":
            step(Tf('para eu parar de perguntar isso a cada rodada, escreva {0}=AUTO no '
                    "seu .env (ligo só o que casa sozinho) ou {1}=NAO (não mexo nas "
                    "contas).", team_check.CHAVE_LIGACAO, team_check.CHAVE_LIGACAO))
    except Exception as e:
        # Ligar a conta e' uma comodidade, nao um pre-requisito: sem isso o curso inteiro
        # continua funcionando com o endereco digitado a mao.
        warn(Tf("não consegui ligar a equipe às contas do ProjectAdm agora: {0}", e))

# 5) O playbook e o proximo prompt — pronto, preenchido, na mao do aluno. Nesta ordem e
#    NESTE PONTO: os cartoes desta rodada ja estao gravados, entao o prompt de cada elo
#    nasce com o quadro de AGORA dentro dele.
resolvidos = escrever_playbook()


def entregar_proximo_elo():
    """O UNICO proximo passo do aluno — com o prompt na mao, pronto para colar.

    Nada de "gere o prompt", "escolha o passo", "abra o arquivo": o script acabou de
    ler o quadro, entao ele SABE em que elo voce esta. Ele monta o prompt daquele elo
    ja preenchido e o poe na sua area de transferencia. Voce da' Ctrl+V na IA.
    """
    elo = contexto.proximo_elo_p1(ids, resolvidos)
    if not elo:
        return None
    print("\n" + "=" * 62)
    print(Tf("  PRÓXIMO (elo {0} de 6): {1}", elo['i'], elo['rotulo']))
    print("=" * 62)
    if elo["decisao"]:
        print(T("  Este elo não é um texto da IA — é a SUA decisão, e é a fronteira do"))
        print(T("  curso. Rode 01a_escolher_abordagem.py: 5 perguntas (os eixos do Guia"))
        print(Tf("  PMBOK 8), ele recomenda e você decide. Depois rode o {0} de novo.",
                 _rotulo_desta_execucao()))
        return elo
    if elo["falta"]:
        print(T("  Antes dele, responda no seu quadro:"))
        for f in elo["falta"]:
            print(Tf("    · cartão {0}", f))
        print(Tf("  Feito isso, rode o {0} de novo — o prompt sai pronto, sozinho.",
                 _rotulo_desta_execucao()))
        return elo
    copiado = copiar(elo["prompt"])
    if copiado:
        print(T("  ✅ O prompt deste elo JÁ ESTÁ NA SUA ÁREA DE TRANSFERÊNCIA — com o seu"))
        print(T("     projeto dentro. Cole na sua IA (Ctrl+V) e mande."))
    else:
        print(Tf('  O prompt deste elo está pronto no cartão "1.{0}" do seu quadro', elo['i']))
        print(Tf("     (e em _saida/prompt-passo-1-{0}-{1}.txt).", elo['i'], elo['chave']))
    print(Tf('     Ele também está no cartão "1.{0}" da lista Referências.', elo['i']))
    if True:
        print(T("\n  Quando a IA responder: copie a resposta INTEIRA e cole no cartão"))
        print(Tf("  \"0. Caixa de entrada\" do quadro. Depois rode o {0} de novo — ele",
                 _rotulo_desta_execucao()))
        print(T("  distribui cada bloco no cartão certo e já te entrega o próximo prompt."))
    return elo


def entregar_complemento_das_partes():
    """O PROCESSO 2 do PMBOK 8 Together — "Identificar as partes interessadas".

    Aqui NAO se repete a pergunta do Termo de Abertura. O elo 3 do Termo ja perguntou
    QUEM esta no projeto; este processo pergunta QUEM MAIS — e o Guia concorda com essa
    ordem: o Termo de Abertura e' ENTRADA de 2.5.2.1.

    Devolve True quando entregou o prompt (ou disse o que falta); False quando ainda nao
    da' para pedir o complemento — e ai quem assume e' a corrente do Termo.
    """
    respostas = respostas_do_termo(ids)
    rot = _rotulo_desta_execucao()
    if not respostas.get("3") or not ids.get("PARTES"):
        # Ninguem identificado ainda: pedir "quem falta" antes de haver alguem seria
        # perguntar do nada. O lugar disso e' o elo 3 do Termo — e e' para la que vai.
        print("\n" + "=" * 62)
        print(Tf("  {0} — {1}", rot, T("Identificar as partes interessadas")))
        print("=" * 62)
        print(T("  Este processo COMPLETA a lista de partes interessadas do seu Termo de"))
        print(T("  Abertura — e o seu Termo ainda não tem nenhuma. Comece por ele: o Guia"))
        print(T("  põe o Termo de Abertura como ENTRADA deste processo (2.5.2.1)."))
        return False

    texto, faltando = contexto.prompt_pronto("partes_completar", ids)
    print("\n" + "=" * 62)
    print(Tf("  {0} — {1}", rot, T("quem MAIS: as partes que ainda não estão na lista")))
    print("=" * 62)
    if faltando:
        print(T("  Antes dele, responda no seu quadro:"))
        for f in faltando:
            print(Tf("    · {0}", prompts.NOME_DO_INPUT.get(f, f)))
        return True
    print(T("  O seu Termo de Abertura já identificou quem o projeto PRECISA. Este"))
    print(T("  processo faz a outra pergunta, a que costuma faltar: quem o projeto"))
    print(T("  AFETA — quem aprova, quem regula, quem opera depois, quem é contra."))
    print(T("  Ninguém que já está no seu quadro volta a ser perguntado."))
    if copiar(texto):
        print(T("\n  ✅ O prompt JÁ ESTÁ NA SUA ÁREA DE TRANSFERÊNCIA — com as suas partes"))
        print(T("     interessadas dentro. Cole na sua IA (Ctrl+V) e mande."))
    else:
        print(T("\n  O prompt está em _saida/prompt-partes-completar.txt"))
    caminho = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                           "_saida", "prompt-partes-completar.txt")
    os.makedirs(os.path.dirname(caminho), exist_ok=True)
    with open(caminho, "w", encoding="utf-8") as fh:
        fh.write(texto + "\n")
    print(T("\n  A resposta vem no bloco [3+] — o \"+\" quer dizer ACRESCENTA: as partes"))
    print(T("  novas entram no seu Termo sem apagar as que já estavam lá. Cole a"))
    print(Tf("  resposta INTEIRA no cartão \"0. Caixa de entrada\" e rode o {0} de", rot))
    print(T("  novo: ele grava as novas e escreve o Registro das Partes Interessadas."))
    print(T("\n  Se a sua IA disser que não falta ninguém, não cole nada: siga em frente."))
    return True


def entregar_proximo():
    """O proximo passo do aluno — que depende de QUEM chamou este script.

    Os dois cursos compartilham este arquivo, e ate' 14/08/2026 o fim dele era um so':
    "entregue o proximo elo do Termo". Rodando o PROCESSO 2 do PMBOK 8 Together isso
    entregava o elo da ABORDAGEM debaixo do titulo "Identificar as partes interessadas"
    — assunto trocado, que e' pior do que repetir a pergunta.
    """
    if _e_o_processo_das_partes() and entregar_complemento_das_partes():
        # Truthy de proposito: quem chama para aqui ("if elo: SystemExit") e o documento
        # deste processo e' escrito pelo processo.py, depois que este script devolve.
        return {"chave": "partes_completar", "rotulo": T("as partes interessadas")}
    return entregar_proximo_elo()


# ── RODADA 1: o quadro esta aberto e as respostas comecaram. O que falta e a DECISAO.
if rodada == 1:
    done(T("Rodada 1 de 2 registrada — a sua justificativa está no quadro."))
    entregar_proximo()
    raise SystemExit(0)

# ── RODADA 2: a abordagem foi escolhida e o quadro inteiro existe. Falta fechar os dois
#    ultimos elos da corrente (o detalhe do COMO, e o QUANDO/QUANTO) — so' entao o
#    termo de abertura esta completo e o passo 2 pode comecar.
done(Tf("Quadro montado na abordagem {0} — {1} listas.",
        prompts.nome_abordagem(abordagem), len(ids)))

elo = entregar_proximo()
if elo:
    raise SystemExit(0)

# Corrente completa: o termo de abertura respondeu as 7 perguntas.
progresso.registrar(1, Tf("Abordagem: {0}. {1} entrega(s), {2} parte(s) interessada(s).",
                          prompts.nome_abordagem(abordagem), len(ENTREGAS), len(PARTES)))
done(T("Passo 1 concluído — o seu projeto está APROVADO, ALINHADO e AUTORIZADO."))
print(T("  Termo de Abertura: as 7 perguntas do 5W2H respondidas, nos cartões do quadro."))

# O grande valor: o quadro JA e o termo de abertura. Entao geramos o DOCUMENTO (Word,
# no visual do template do curso) lendo o quadro — voce nao copia nada. Subproduto de
# concluir o passo (como os prompts), nunca uma acao a mais. Nunca derruba o passo.
try:
    caminho, _av = artefatos.gerar_termo_de_abertura(ids, abordagem, projeto)
    print(Tf('\n  📄 Termo de Abertura gerado em Word: _saida/documentos/{0}', os.path.basename(caminho)))
    print(T("     (no visual do template do curso — pronto para compartilhar ou imprimir;"))
    print(T("      regenere quando quiser pela tecla D do menu, ou editando os cartões)."))
except Exception as e:
    warn(Tf("não consegui gerar o Termo de Abertura em Word agora ({0}).", e))
    print(T("     Você pode gerá-lo a qualquer momento: menu → tecla D (Gerar meus documentos)."))

# Conferencias automaticas do Passo 1 (OKR, entregas, requisitos): a maquina ajuda a ver
# o que ainda falta e marca no quadro o que precisa de revisao; a revisao continua sendo
# sua. Nunca trava o passo.
try:
    import passos
    passos.conferir(1, ids, abordagem)
except Exception as e:
    warn(Tf("não consegui rodar as conferências automáticas do Passo 1 agora ({0}).", e))

# O Passo 1 e' rodado de novo em varias situacoes — inclusive AUTOMATICAMENTE a cada
# "Atualizar a versao do curso". Se ele reancorasse sempre em "-> Passo 2", o aluno que
# ja fez ate o Passo 6 via, apos uma atualizacao, "voce esta comecando o Passo 2" — o
# bug que o Eduardo relatou (2026-07-15). A verdade esta no QUADRO: leia a trilha
# concluida e diga onde o aluno esta DE FATO.
feitos = progresso.feitos()
avancou = sorted(x for x in feitos if 2 <= x <= 10)
if avancou:
    prox = next((x for x in range(2, 11) if x not in feitos), None)
    print(Tf('\n  A SUA TRILHA (lida do quadro): {0}', ' '.join(('✓' + str(x) for x in avancou))))
    if prox:
        print(Tf("  ▶ Próximo: Passo {0}. Escolha-o no menu — ao rodar, ele já te", prox))
        print(T("     entrega o prompt pronto, com a foto do seu quadro dentro."))
    else:
        print(T("  🏁 Você percorreu os 10 passos. Parabéns!"))
else:
    caminho = contexto.gerar_prompt_pronto(2, ids)
    if caminho:
        if copiar(contexto.corpo_prompt_passo(2, ids)[0]):
            print(T("\n  ✅ O prompt do PASSO 2 já está na sua ÁREA DE TRANSFERÊNCIA — com o"))
            print(T("     seu projeto dentro (e no cartão \"02 - Passo 2\" da lista Referências)."))
        else:
            # SEM o numero na frase: o arquivo se chama `prompt-passo-2` nos dois cursos
            # (renomea-lo seria migracao), e no curso de 40 a frase saía "PROCESSO 5 ...
            # prompt-passo-2.txt" — dois numeros diferentes na mesma linha, e o aluno
            # procurando um arquivo que nao existe. O numero aparece uma vez so': no nome.
            print(T("\n  O prompt do PRÓXIMO PASSO já está pronto em _saida/prompt-passo-2.txt"))
            print(T("     (e no cartão \"02 - Passo 2\" da lista Referências)."))
        if True:
            print(T("\n  O RITMO É SEMPRE O MESMO:"))
            print(T("    1. Abra o menu e escolha o Passo 2."))
            print(T("    2. Cole o prompt na sua IA (Ctrl+V)."))
            print(T("    3. Copie a resposta INTEIRA dela (ela começa com [P2]) e cole no"))
            print(T("       cartão \"0. Caixa de entrada\" do seu quadro."))
            print(T("    4. Rode o Passo 2 de novo — ele lê o quadro e monta o seu escopo."))
    else:
        print(T("\n  Complete as ENTREGAS (cartão 2.1) para o passo 2 já sair pronto."))
