"""
Project Together — powered by AI: os cartoes da lista "Referencias e Passos".

E o playbook do curso DENTRO do quadro do aluno: um cartao por passo, com o que
fazer, o prompt daquele passo (no tipo de IA dele) e o script que executa. O aluno
nunca precisa voltar ao e-mail para saber o que vem agora — o proximo passo esta
no proprio quadro.

Os prompts vem de prompts.py (fonte unica: o mesmo texto que o contexto.py usa
para gerar os prompts ja preenchidos).
"""
import re

from prompts import (montar_prompt, NOME_DO_INPUT, chave_do_passo, nome_abordagem,
                     normalizar_abordagem, CORRENTE_P1, DESTRAVAR_JUSTIFICATIVA,
                     EXPLICAR_CONCEITO)
from idioma import T, Tf

# Um caminho so' (o modo IDE saiu em 01/08): a IA no navegador devolve texto, o
# aluno cola na Caixa de entrada, o script le o quadro. Ele nunca edita um arquivo.
COMO_RODAR = ("Cole o prompt na sua IA (navegador). Ela devolve um bloco rotulado "
              "([1.2], [P2]...); copie a resposta INTEIRA e cole no cartão "
              "\"0. Caixa de entrada\" do seu quadro. Depois rode o passo pelo menu — "
              "ele lê o quadro e distribui tudo. Você não edita arquivo nenhum.")

# (numero, titulo, o que e este passo, script)
PASSOS = [
    (0, T("Configurar o ambiente"),
     T("ProjectAdm + a sua IA + estes scripts. Você já fez isso se está lendo este "
     "cartão: ele nasceu aqui pelo script.\n"
     "Artigo: escritoriodeprojetos.com.br/instalacao-e-configuracao/"),
     None),
    (1, T("Iniciar o projeto (5W2H)"),
     T("Autorizar o projeto: POR QUÊ · O QUÊ · QUEM · COMO (e o ONDE) · QUANDO · QUANTO.\n"
     "VOCÊ escreve a justificativa. A IA propõe o resto, elo por elo, em cima dela.\n"
     "O COMO é a ABORDAGEM DE DESENVOLVIMENTO — rode 01a_escolher_abordagem.py: 5 "
     "perguntas (os eixos do Guia PMBOK 8) e ele grava a sua escolha no .env. É ela que "
     "monta este quadro — e é ela que define como se calcula o quando, o quanto e o "
     "onde."),
     "01_iniciar_projeto.py"),
    (2, T("Revisar o escopo"),
     T("O O QUÊ, no nível em que o trabalho acontece.\n"
     "PREDITIVA: a EAP (entregas -> pacotes de trabalho).\n"
     "ÁGIL: a META DO PRODUTO + o Product Backlog priorizado por valor.\n"
     "A Meta do Produto é o COMPROMISSO do Product Backlog (Guia Scrum): o estado que, "
     "atingido, permite encerrar o projeto. Ela é a régua da ordem — cada item responde "
     "'isto me aproxima da meta?'. Cada artefato tem o seu compromisso: Product Backlog "
     "-> Meta do Produto · Sprint Backlog -> Meta da Sprint (passo 5) · Incremento -> "
     "Definição de Pronto (passo 5)."),
     "02_escopo.py"),
    (3, T("Analisar os riscos"),
     T("O que pode dar errado — e o que pode dar muito certo.\n"
     "Escreva o risco como CAUSA -> EVENTO -> IMPACTO. 'Atraso' não é risco: é impacto.\n"
     "ÁGIL: a incerteza de conhecimento vira SPIKE no backlog (investigar com tempo fixo)."),
     "03_riscos.py"),
    (4, T("Cronograma e orçamento"),
     T("QUANDO e QUANTO, agora com número.\n"
     "PREDITIVA: datas e dependências nos pacotes + orçamento com reserva.\n"
     "ÁGIL: roadmap por Sprints (a data é fixa; o escopo flutua) + custo por Sprint."),
     "04_cronograma_orcamento.py"),
    (5, T("Revisar e aprovar o plano"),
     T("Aprovar não é assinar: é CAPTURAR A BASELINE do quadro — a foto do plano "
     "aprovado. A partir dela, toda mudança tem custo visível (passo 9).\n"
     "ÁGIL: este passo é a SPRINT PLANNING — os três tópicos do Guia Scrum: a Meta da "
     "Sprint (por quê), os itens que entram (o quê) e as tarefas de até um dia (como). "
     "Aqui também nasce a Definição de Pronto (DoD) — genérica, do projeto inteiro: a "
     "validação de cada item mora no critério de aceitação dele, escrito no passo 2."),
     "05_aprovar_plano.py"),
    (6, T("Engajar as partes interessadas"),
     T("Projeto não morre de cronograma. Morre de gente que não foi ouvida.\n"
     "Para cada parte: de onde ela está (resistente/neutro/apoiador/líder) para onde "
     "precisa estar — e a estratégia concreta que leva ela até lá."),
     "06_engajar_partes.py"),
    (7, T("Orientar e executar"),
     T("Fazer o trabalho acontecer.\n"
     "PREDITIVA: as próximas ações do caminho crítico.\n"
     "ÁGIL: a DAILY SCRUM — rode todo dia útil (15 min): o foco de hoje rumo à Meta da "
     "Sprint, os impedimentos (quem remove cada um) e as tarefas que apareceram."),
     "07_executar.py"),
    (8, T("Monitorar e Status Report"),
     T("O quadro já sabe onde você está: o script LÊ os cartões (planejado x realizado, "
     "orçamento, riscos) e a IA escreve o Status Report para quem decide — veredito "
     "primeiro, explicação depois.\n"
     "ÁGIL: este passo é a SPRINT REVIEW — item que atende a TODA a Definição de Pronto "
     "vira Incremento; item que não atende volta ao Product Backlog. Não existe 80% "
     "pronto.\n"
     "⏱️ Quando rodar: sempre que precisar comunicar o andamento às partes ou checar a "
     "saúde do projeto. É contínuo — não um evento no fim."),
     "08_status_report.py"),
    (9, T("Controlar mudanças"),
     T("Tudo muda. Projeto sério é o que sabe o que a mudança CUSTA.\n"
     "PREDITIVA: análise de impacto contra a baseline (escopo, prazo, custo, risco).\n"
     "ÁGIL: repriorização do backlog — o que entra, e o que sai para caber — e o "
     "REFINAMENTO do topo do backlog (atividade contínua, não evento com hora marcada).\n"
     "⏱️ Quando rodar: sempre que chegar um pedido de mudança — a qualquer momento."),
     "09_mudancas.py"),
    (10, T("Encerrar e verificar o valor"),
     T("Encerrar não é 'acabou': é provar se o valor prometido chegou. Compare o "
     "realizado com os Key Results do passo 1 — e registre as lições que você levaria "
     "para o próximo projeto.\n"
     "ÁGIL: este passo é a SPRINT RETROSPECTIVE — ela CONCLUI a Sprint. Olha o COMO o "
     "time trabalhou (a Review olhou o produto) e termina em até 3 ações de melhoria, que "
     "entram no Sprint Backlog da próxima. Depois dela o ciclo volta ao passo 5."),
     "10_encerrar.py"),
]


_ELO_TITULO = {
    "okr": T("Prompt 1 — os objetivos (OKR), a partir da sua justificativa"),
    "entregas": T("Prompt 2 — as entregas, a partir dos objetivos"),
    "partes": T("Prompt 3 — as partes interessadas, a partir das entregas"),
    "abordagem": T("Prompt 4 — COMO: a abordagem de desenvolvimento (destranca o quadro)"),
    "restricoes_premissas_riscos":
        T("Prompt 5 — o detalhe do COMO: restrições, premissas, riscos e ONDE"),
    "quando_quanto": T("Prompt 6 — quando e quanto (preliminar), já na sua abordagem"),
}
_ELO_NOTA = {
    "okr": T("Antes deste prompt, ESCREVA a sua justificativa (cartão 1.1 da lista INPUTS). "
           "Ela é sua — a IA não a escreve. Travou? Veja o cartão 90."),
    "abordagem": T("ESTE ELO É UMA DECISÃO SUA, NÃO UM TEXTO DA IA — e é a FRONTEIRA do "
                 "curso. Enquanto você não escolhe o COMO, fica trancado tudo o que "
                 "depende dele: o bloco 4 do termo de abertura (incluindo o ONDE), os "
                 "cartões 5 (QUANDO) e 6 (QUANTO) e as listas de trabalho do quadro.\n"
                 "Por que aqui? Porque a abordagem se ESCOLHE a partir do por quê, do o "
                 "quê e do quem (os fatores do Guia PMBOK 8) — e porque é ela que define "
                 "como se CALCULA o quando, o quanto e o onde. Perguntar 'quando fica "
                 "pronto?' antes é pedir um número sem saber o que ele significa: marco "
                 "de entrega ou fim de Sprint?\n"
                 "Rode o script 01a_escolher_abordagem.py: 5 perguntas (os eixos do "
                 "Guia PMBOK 8), ele recomenda e VOCÊ decide. Ele grava ABORDAGEM no .env "
                 "e já monta este prompt preenchido em _saida/prompt-abordagem.txt — "
                 "a IA dá a segunda opinião (pode discordar; ótimo).\n"
                 "Depois, rode 01_iniciar_projeto.py de novo: ele destranca o resto do "
                 "termo e monta o quadro na sua abordagem."),
    "restricoes_premissas_riscos":
        T("Rode este prompt DEPOIS de escolher a abordagem: no ágil a premissa vira "
        "hipótese (a Sprint 1 existe para testá-la) e o risco entra no backlog; na "
        "preditiva eles viram registro e resposta planejada.\n"
        "O ONDE entra aqui porque ele é PARTE DO COMO: onde o trabalho acontece depende "
        "de como você vai conduzi-lo. É a menos decisiva das sete perguntas — se você "
        "ainda não sabe, deixe o cartão 4.6 em branco e decida no momento certo. O que "
        "vale nele é o que fica de FORA."),
    "quando_quanto":
        T("Por último — e de propósito. O COMO é que define como se calcula o QUANDO e o "
        "QUANTO: na preditiva o marco é a entrega concluída e o custo é o do projeto; no "
        "ágil o marco é o primeiro incremento útil e o custo é o do time por Sprint (a "
        "data tende a ser fixa; o escopo é que flutua).\n"
        "Aqui ainda é ORDEM DE GRANDEZA: o número com nome e sobrenome vem no passo 4."),
}


# Fallback quando o cartao e' montado sem consultar o quadro (ex.: um quadro-modelo
# em construcao). O caso normal traz os [INPUT x] que faltam, vindos do proprio prompt.
_ELO_FALTA = {
    "okr": T('a sua justificativa (cartão "1.1")'),
    "entregas": T('os seus objetivos (cartão "1.2")'),
    "partes": T('as suas entregas (cartão "2.1")'),
    "restricoes_premissas_riscos": T("a sua abordagem (rode 01a_escolher_abordagem.py)"),
    "quando_quanto": T("a sua abordagem (rode 01a_escolher_abordagem.py)"),
}

_PRONTO = (
    T("✅ PRONTO PARA COPIAR — este prompt já está PREENCHIDO com o que VOCÊ respondeu "
    "no quadro. O script leu os seus cartões e montou o prompt inteiro.\n"
    "Não copie mais nada de lugar nenhum: selecione tudo abaixo da linha, cole na sua "
    "IA e traga a resposta INTEIRA de volta para o cartão \"0. Caixa de entrada\"."))

_AINDA_NAO = (
    T("⏳ Este prompt fica pronto — com o SEU texto dentro — assim que você responder "
    "{falta} e rodar o Passo 1 de novo.\n"
    "Você nunca precisa copiar o conteúdo de um cartão para dentro de um prompt: o "
    "script lê o quadro e preenche por você."))


def cards_da_corrente_p1(resolvidos=None):
    """Os 6 elos do Passo 1, um cartao cada (viram subtarefas do cartao 01).

    Cada elo come a saida do anterior — e cada um preenche uma secao do Termo de
    Abertura 5W2H (que sao os cartoes da lista 'INPUTS' e as secoes do documento
    que o passo 1 gera). A corrente e o curso.

    `resolvidos` = {chave: (prompt pronto, [inputs que faltam])}, de
    contexto.prompts_da_corrente(). Com ele, o prompt do elo entra no cartao JA
    PREENCHIDO com o que o aluno respondeu — em vez de um «cole aqui a sua
    justificativa» que o obrigaria a copiar, na mao, um texto que esta a dois cartoes
    dali. Sem ele (quadro recem-aberto), o cartao diz o que responder para o prompt
    nascer pronto.
    """
    resolvidos = resolvidos or {}
    cards = []
    for i, chave in enumerate(CORRENTE_P1, 1):
        texto, faltando = resolvidos.get(chave, (None, None))
        pronto = bool(texto) and not faltando
        corpo = [f"ELO {i} de 6 da corrente do Passo 1.", ""]
        if chave != "abordagem":
            if pronto:
                corpo += [_PRONTO, ""]
            else:
                falta = ", ".join(NOME_DO_INPUT.get(f, f) for f in (faltando or [])) \
                        or _ELO_FALTA.get(chave, "os cartões anteriores")
                corpo += [_AINDA_NAO.format(falta=falta), ""]
        if _ELO_NOTA.get(chave):
            corpo += [_ELO_NOTA[chave], ""]
        if chave == "abordagem":
            pass                                   # nao ha prompt: ha uma decisao (01a)
        elif pronto:
            corpo += ["-" * 56, texto]
        else:
            corpo += ["(o prompt aparece aqui, pronto, na próxima vez que você rodar "
                      "o Passo 1)"]
        cards.append((f"1.{i} {_ELO_TITULO[chave]}", "\n".join(corpo)))
    return cards


_SOFT = {"5", "6", "4.6"}


def _card_passo(n, titulo, o_que, script, abordagem, prompt_resolvido=None):
    partes = [o_que, ""]
    if script:
        # "COMO RODAR" era f-string crua e o parágrafo vinha de uma VARIÁVEL dentro do
        # T() — os dois passavam pelos lints (que só coletam literais escritos dentro de
        # T(...)), e os 11 cartões da lista Referências saíam com um parágrafo inteiro em
        # português no quadro em inglês (Eduardo, quadro 324, 06/08/2026).
        partes += [Tf("SCRIPT: {0}", script),
                   Tf("COMO RODAR: {0}", T(COMO_RODAR)), ""]
    if n == 1:
        partes.append(
            T("OS 6 PROMPTS DESTE PASSO ESTÃO NAS SUBTAREFAS DESTE CARTÃO — na ordem da "
            "corrente: cada um come a saída do anterior. E a ordem da corrente é a ordem "
            "do próprio Termo de Abertura: 1 por quê · 2 o quê · 3 quem · 4 como · "
            "5 quando · 6 quanto.\n"
            "  1.1 objetivos (OKR)  ->  1.2 entregas  ->  1.3 partes interessadas  ->\n"
            "  1.4 COMO: a abordagem (a sua decisão)  ->  1.5 restrições, premissas,\n"
            "  riscos e o ONDE  ->  1.6 quando e quanto (preliminar)\n\n"
            "Cada elo preenche uma seção do Termo de Abertura 5W2H — que são os cartões "
            "da lista 'INPUTS (Projeto 5W2H)' e as seções do documento que o script gera "
            "no fim.\n\n"
            "O ELO 1.4 É A FRONTEIRA. Até você escolher a abordagem fica trancado tudo o "
            "que depende dela: o bloco COMO (4.1 a 4.6, onde mora também o ONDE), o "
            "QUANDO (5), o QUANTO (6) e as listas de trabalho do quadro. Escolhida a "
            "abordagem, rode 01_iniciar_projeto.py de novo — ele destranca o resto e "
            "monta o quadro na forma dela."))
    elif n >= 2 and not abordagem:
        partes.append(
            T("O prompt deste passo tem forma diferente em cada abordagem — ele aparece "
            "aqui assim que você escolher o COMO (elo 1.5 do Passo 1)."))
    elif n >= 2:
        chave = chave_do_passo(n, abordagem)
        if chave:
            partes.append(Tf('PROMPT (abordagem {0}):\n\n{1}',
                             nome_abordagem(abordagem), montar_prompt(chave)))
            partes.append(Tf('\n Dica: depois do passo anterior, este prompt já sai PRONTO, '
                             'com o seu projeto dentro, em _saida/prompt-passo-{0}.txt.', n))
        else:
            # Passo sem IA nesta abordagem (ex.: Passo 5 na preditiva): a revisão é do
            # aluno; o python só faz as conferências mecânicas para ajudar.
            partes.append(
                Tf("Neste passo, a revisão do plano é SUA — não use IA para caçar lacunas (ela "
                   "só vê o resumo e chuta). Ao rodá-lo, fazemos algumas conferências "
                   "automáticas para ajudar (há entrega para cada KR? todo risco tem "
                   "probabilidade, impacto, resposta e dono? todo pacote tem data e "
                   "responsável? o orçamento fecha?) e apontamos o que falta; você revisa e "
                   "decide."))
    # O NUMERO do cartao nunca muda (e' por ele que o aluno acha o passo, e e' a FORMA
    # que o e_cartao_do_curso reconhece); o NOME sai na abordagem dele — no agil, os
    # passos do ciclo da Sprint viram o evento do Guia Scrum. Ver prompts.rotulo.
    from prompts import rotulo
    # O cartao 00 e' a CONFIGURACAO DO AMBIENTE — nao e' passo do metodo nem processo do
    # Guia. Carimba-lo com uma unidade inventaria um "Processo 0" que o PMBOK 8 nao tem.
    if n == 0:
        return (Tf("{0} - {1}", f"{n:02d}", rotulo(n, abordagem, base=titulo)),
                "\n".join(partes).strip())
    return (Tf("{0} - Passo {1}: {2}", f"{n:02d}", n,
               rotulo(n, abordagem, base=titulo)),
            "\n".join(partes).strip())


def build_cards(abordagem=None):
    """Os cartoes da Referencia, na ordem (00 -> 99), para o tipo de IA e a
    abordagem do aluno.

    abordagem=None (ETAPA 1, antes da escolha do COMO): o roteiro dos 10 passos
    aparece inteiro — mas os passos 2 a 10 ainda nao trazem o prompt, porque o
    prompt deles depende da abordagem. Nada de prometer uma forma que ainda nao
    foi decidida.
    """
    abordagem = normalizar_abordagem(abordagem) if abordagem else None
    cards = [_card_passo(n, t, o, s, abordagem) for n, t, o, s in PASSOS]
    cards.append((
        "90 - Travou na justificativa? (prompt de apoio)",
        "A justificativa é o único texto que a IA NÃO escreve por você — é a sua dor "
        "e o seu contexto. Mas ela pode te ajudar a puxá-la de dentro, com perguntas.\n\n"
        + DESTRAVAR_JUSTIFICATIVA))
    cards.append((
        "91 - Não entendeu um termo? (prompt do professor)",
        "Neste curso nenhum termo aparece sem explicação. Se algum escapou, pergunte:\n\n"
        + EXPLICAR_CONCEITO))
    cards.append((
        "99 - Como este quadro funciona",
        "A lista INPUTS deste quadro são as 7 perguntas do 5W2H — as MESMAS nas duas "
        "abordagens de desenvolvimento (Guia PMBOK 8). O que muda é a FORMA da "
        "resposta.\n\n"
        "O QUADRO É MONTADO EM DUAS ETAPAS, e ele acompanha a sua leitura:\n\n"
        "1) AGORA: você responde o começo do 5W2H nos cartões da lista INPUTS, um por "
        "vez, conforme lê o Passo 1 — 1.1 justificativa, 1.2 objetivos, 2.1 e 2.2 o "
        "quê, 3 quem. Da fronteira para baixo, tudo nasce TRANCADO: o bloco COMO "
        "(4.1 a 4.6 — o ONDE é parte dele) e os cartões 5 (QUANDO) e 6 (QUANTO).\n\n"
        "2) DEPOIS DE ESCOLHER A ABORDAGEM (o COMO — script 01a_escolher_abordagem.py): "
        "rode 01_iniciar_projeto.py de novo. Ele destranca o resto do termo e monta o "
        "quadro na forma da SUA abordagem:\n"
        "   PREDITIVA: EAP → Cronograma (o status vive no cartão — sem listas de fluxo)\n"
        "   ÁGIL:      Product Backlog · Sprint Backlog · Incremento (Pronto)\n\n"
        "Por que não montar tudo de uma vez? Porque a ordem do curso é a ordem certa de "
        "pensar, e ela tem duas metades:\n"
        "· escolher o COMO antes de saber o POR QUÊ, o O QUÊ e o QUEM seria chute — são "
        "exatamente esses os fatores que o Guia PMBOK 8 manda usar para escolher a "
        "abordagem;\n"
        "· e o QUANDO, o QUANTO e o ONDE se calculam A PARTIR do COMO: o marco é uma "
        "entrega concluída ou o fim de uma Sprint? O custo é o do projeto ou o do time "
        "por Sprint? Sem a abordagem, é número sem significado.\n\n"
        "REGRA DE OURO: você escreve primeiro, a IA propõe em cima, você decide.\n"
        "A memória do seu projeto fica em _saida/contexto.md — e o prompt do próximo "
        "passo sempre sai pronto em _saida/prompt-passo-N.txt."))
    # O VOCABULARIO DO CURSO, uma vez, na saida. Os corpos dos cartoes 90/91/99 sao
    # texto solto (nao passam pelo T(), como os numerados passam), e eram os ultimos
    # lugares onde o quadro do aluno de 40 processos ainda dizia "Passo". Filtrar aqui
    # e' idempotente: nos cartoes que ja' vieram traduzidos nao sobrou o que trocar.
    try:
        import catalogo_pmbok8
        cards = [(catalogo_pmbok8.reescrever_unidade(t),
                  catalogo_pmbok8.reescrever_unidade(d)) for t, d in cards]
    except Exception:
        pass                       # sem catalogo em maos, o playbook sai como sempre saiu
    return cards


def all_titles():
    """Titulos de TODOS os modos e etapas (o configurador usa para limpar cards antigos:
    o que era etapa 1 tem de sumir quando a etapa 2 recria o playbook)."""
    t = set()
    for ab in (None, "PREDITIVA", "AGIL"):
        t |= {titulo for titulo, _d in build_cards(ab)}
    t |= {titulo for titulo, _d in cards_da_corrente_p1()}
    return t


# Os cartoes que o CURSO gera vivem em dois "sobrenomes" — e nenhum aluno batiza um
# cartao assim. Reconhece-los pela FORMA (e nao pelo titulo exato) e o que permite
# apagar a versao antiga de um cartao que MUDOU DE NOME.
_FORMA_DE_CARTAO_DO_CURSO = (
    re.compile(r"^\d{2} - "),           # 00..10 (os passos), 90, 91, 99 (apoio)
    re.compile(r"^1\.\d Prompt \d"),    # os elos da corrente do Passo 1
)


def e_cartao_do_curso(titulo):
    """True se este cartao foi gerado pelo curso — em QUALQUER versao dele.

    Por titulo exato nao bastava: quando a corrente do Passo 1 foi reordenada, o elo
    "1.4 Prompt 4 — onde, quando e quanto" deixou de existir. Como o titulo antigo nao
    estava mais na lista de titulos atuais, o cartao velho SOBREVIVIA — e o aluno
    ficava com dois "Prompt 4" no quadro, um deles com o prompt errado.
    """
    t = (titulo or "").strip()
    return t in all_titles() or any(p.match(t) for p in _FORMA_DE_CARTAO_DO_CURSO)
