"""
Together Kit — o VOCABULARIO que o curso reconhece na resposta da IA.

POR QUE ISTO EXISTE
    O curso entrega um prompt e le de volta o que a IA respondeu. O prompt diz
    "escreva `probabilidade:`"; o parser (entradas.py) procura `probabilidade:`.
    Traduzir o prompt para ingles sem traduzir o parser quebraria o curso inteiro
    de um jeito silencioso: a IA responde `probability:`, o parser nao acha nada, o
    cartao volta vazio e o aluno acha que a culpa e' dele.

    Entao o parser aprende os DOIS vocabularios, SEMPRE — nao conforme o IDIOMA.
    Isso vale mais do que parece:
      · o aluno brasileiro cuja IA respondeu em ingles (acontece o tempo todo com
        modelo configurado em ingles) continua sendo lido;
      · o aluno americano que cola um exemplo em portugues do artigo, idem;
      · e nao existe um "modo" para dar errado — nao ha bifurcacao para testar.

    A forma canonica e' sempre a PORTUGUESA (o resto do codigo ja fala por ela).
    Aqui so' se ACRESCENTA sinonimo; nunca se troca o canonico, senao quebra o
    curso em portugues, que e' o que esta no ar.

COMO ACRESCENTAR
    Chave = como a IA pode escrever (sem acento, minusculas). Valor = o canonico
    que o codigo ja usa. Rode os testes de entradas.py depois.
"""

# ─────────────────────────────────────────────────────────────────────────────
# CAMPOS  ('probability: high'  ->  'probabilidade')
# ─────────────────────────────────────────────────────────────────────────────
CAMPOS = {
    # risco / ponto de atencao
    "probability": "probabilidade",
    "likelihood": "probabilidade",
    "urgency": "urgencia",
    "impact": "impacto",
    "severity": "gravidade",
    "priority": "prioridade",
    "response": "resposta",
    "risk response": "resposta",
    "owner": "dono",
    "risk owner": "dono",
    "type": "tipo",
    "risk": "risco",
    # escopo
    "requirement": "requisito",
    "acceptance": "criterio de aceitacao",
    "acceptance criterion": "criterio de aceitacao",
    "acceptance criteria": "criterio de aceitacao",
    "serves kr": "serve ao kr",
    "serves which kr": "serve ao kr",
    "kr": "serve ao kr",
    "deliverable": "entrega",
    "phase": "fase",
    "work package": "pacote",
    "package": "pacote",
    "parent": "dentro de",
    "inside": "dentro de",
    "within": "dentro de",
    "after": "depois de",
    "code": "codigo",
    "name": "nome",
    # cronograma e orcamento
    "duration": "duracao",
    "start": "inicio",
    "start date": "inicio",
    "end": "fim",
    "finish": "fim",
    "end date": "fim",
    "depends on": "depende de",
    "predecessor": "depende de",
    "responsible": "responsavel",
    "assignee": "responsavel",
    "assigned to": "responsavel",
    "value": "valor",
    "amount": "valor",
    "cost": "valor",
    "when": "quando",
    "by": "ate",
    "due": "ate",
    "due date": "ate",
    "unblocks": "desbloqueia",
    "estimate": "estimativa",
    # OKR
    "target": "meta",
    "provisional target": "meta provisoria",
    "preliminary target": "meta preliminar",
    "deadline": "prazo",
    # partes interessadas
    "power": "poder",
    "interest": "interesse",
    "role": "papel",
    "expects": "espera",
    "expectation": "espera",
    "group": "grupo",
    "current": "atual",
    "desired": "desejado",
    "strategy": "estrategia",
    # agil
    "points": "pontos",
    "story points": "pontos",
    "item": "item",
    "backlog item": "item",
    "sprint goal": "meta da sprint",
    "affects": "afeta",
    "who removes": "quem remove",
    "missing": "faltou",
    "what is missing": "faltou",
    "definition of done": "definicao de pronto",
    "not completed": "nao concluido",
    "backlog change": "muda no backlog",
    # status report / encerramento
    "evidence": "evidencia",
    "impact if no action": "impacto se nao agir",
    "who decides": "de quem",
    "options": "opcoes",
    "how will i know it worked": "como saberei que funcionou",
    "lessons learned": "licoes aprendidas",
    # encerramento e retrospectiva (Passo 10)
    "actual": "realizado",
    "achieved": "atingido",
    "why": "por que",
    "what happened": "o que aconteceu",
    "what i would do differently": "o que eu faria diferente",
    "useful for": "serve para",
    "after": "apos",
    # analise de impacto de mudanca (Passo 9)
    "scope": "escopo",
    "time": "prazo",
    "cost impact": "custo",
    "quality": "qualidade",
    "risks": "riscos",
    "stakeholders": "partes interessadas",
    "where it enters the backlog": "onde entra no backlog",
    "what drops out to fit": "o que sai ou desce para caber",
}

# ─────────────────────────────────────────────────────────────────────────────
# SECOES  (o cabecalho 'RISKS:' abre a secao que o codigo chama de 'RISCOS')
# ─────────────────────────────────────────────────────────────────────────────
SECOES = {
    "risks": "RISCOS",
    "assumptions": "PREMISSAS",
    "constraints": "RESTRICOES",
    "schedule": "CRONOGRAMA",
    "budget": "ORCAMENTO",
    "cost": "ORCAMENTO",
    "summary": "RESUMO",
    "alerts": "ALERTAS",
    "decisions": "DECISOES",
    "actions": "ACOES",
    "items": "ITENS",
    "goal": "META",
    "sprint goal": "META DA SPRINT",
    "dod": "DOD",
    "definition of done": "DEFINICAO DE PRONTO",
    "increment": "INCREMENTO",
    "not done": "NAO_CONCLUIDO",
    "not_done": "NAO_CONCLUIDO",
    "not completed": "NAO CONCLUIDO",
    "not_completed": "NAO_CONCLUIDO",
    "impediments": "IMPEDIMENTOS",
    "blockers": "IMPEDIMENTOS",
    "focus": "FOCO",
    "tasks": "TAREFAS",
    "lessons": "LICOES",
    "lessons learned": "LICOES APRENDIDAS",
    "recommendation": "RECOMENDACAO",
    "result": "RESULTADO",
    "okr result": "RESULTADO_OKR",
    "okr_result": "RESULTADO_OKR",
    "closing": "ENCERRANDO",
    "feedback": "FEEDBACK",
    "request": "SOLICITACAO",
    "change request": "SOLICITACAO",
    "impact": "IMPACTO",
    "remove": "REMOVER",
    "schedule change": "CRONOGRAMA",
}

# ─────────────────────────────────────────────────────────────────────────────
# VALORES — as palavras que aparecem DEPOIS do 'campo:'.
#
# Sao fragmentos (radicais), nao palavras inteiras: quem os consome usa `in`, para
# aceitar 'muito alta', 'alto' e 'altissimo' com a mesma regra.
# ─────────────────────────────────────────────────────────────────────────────
# Escala de 1 a 5 (probabilidade, urgencia, impacto)
NIVEL_MUITO = ("muito", "very", "extremely")
NIVEL_BAIXO = ("baix", "low", "minor")
NIVEL_MEDIO = ("medi", "moderate", "average")
NIVEL_ALTO = ("alt", "high", "major", "critical", "sever")

# Tipo do ponto de atencao. A ORDEM importa: 'restric' antes de 'risco', porque um
# texto pode citar os dois e o primeiro achado ganha.
#
# AMEACA E OPORTUNIDADE SAO TIPOS, NAO SINONIMOS DE "RISCO" (Eduardo, 18/08/2026)
#     Ate' aqui os dois caiam em "Risco", e o cartao do quadro sabia a diferenca
#     (🔴 AMEACA / 🟢 OPORTUNIDADE) enquanto o Registro dos pontos de atencao a perdia:
#     a coluna Tipo dizia "Risco" nas duas. Quem abria a planilha nao tinha como
#     separar o que pode dar errado do que pode dar muito certo — e sao decisoes
#     opostas (mitigar x explorar). O modelo do curso passou a oferecer os seis tipos
#     na lista da coluna Tipo, e o codigo passa a escrever qual e' qual.
#
#     "Risco" continua existindo, e nao e' sobra: e' o ponto ainda nao qualificado — o
#     "evento que, se ocorrer, pode ter impacto positivo OU negativo". E' o que sai
#     quando o cartao nao traz marca nenhuma (cartao antigo, ou escrito a mao).
TIPO_PONTO = (
    ("restric", "Restrição"), ("constraint", "Restrição"),
    ("premissa", "Premissa"), ("assumption", "Premissa"),
    # IMPEDIMENTO E' PROBLEMA, e nao "risco" (18/08/2026). O cartao 🚧 que a Daily abre
    # na lista de riscos comeca por "Impedimento levantado na Daily de..." — nenhuma das
    # chaves acima casava, entao ele caia no "Risco" do fim e chegava ao registro tipado
    # como uma incerteza. Impedimento e' o que JA' esta' travando o time: e' o risco que
    # aconteceu, que e' exatamente a definicao de Problema. Serve aos dois idiomas
    # ("impedimento" contem "impediment").
    ("problema", "Problema"), ("issue", "Problema"), ("impediment", "Problema"),
    ("oportun", "Oportunidade"), ("opportun", "Oportunidade"),
    ("ameac", "Ameaça"), ("threat", "Ameaça"),
    # POR ULTIMO, e de proposito: "⚪ RISCO" e' o ponto ainda NAO qualificado, e as
    # chaves acima tem de ganhar dele. Ele existe para a marca da 1a linha decidir o
    # tipo sozinha — sem ela, um cartao com a palavra "problema" no meio do enunciado
    # ("resolver o problema de acesso") era lido como Problema pela busca no corpo.
    ("risco", "Risco"), ("risk", "Risco"),
)

# OS TIPOS QUE SE AVALIAM por probabilidade x impacto — e que por isso levam
# prioridade, resposta e dono. Premissa e Restricao NAO: elas se confirmam ou se
# respeitam, nao se calculam.
#
# Uma definicao SO', aqui, porque ate' 18/08/2026 esta regra vivia como o literal
# `("Risco", "Problema")` repetido em oito lugares (artefatos, auditoria, quadro,
# engenharia reversa). Acrescentar dois tipos com a regra espalhada assim seria
# consertar sete e esquecer um — e o esquecido nao daria erro: ele so' deixaria de
# calcular a prioridade de uma ameaca, em silencio.
TIPOS_AVALIAVEIS = ("Risco", "Problema", "Ameaça", "Oportunidade")


def avaliavel(tipo):
    """Este tipo de ponto de atencao se avalia por probabilidade x impacto?"""
    return (tipo or "") in TIPOS_AVALIAVEIS

# Prefixos que o titulo de um cartao pode trazer e que o campo Tipo ja diz.
PREFIXO_TIPO = (r"premissas?|restri[cç][aã]o|restricoes|restricao|"
                r"assumptions?|constraints?")

# Rotulos que DELIMITAM o valor de um campo quando o editor junta tudo na mesma
# linha. E' uma alternativa de regex — por isso vem como texto, nao como lista.
# A DURACAO entrou em 06/08/2026: o Passo 4 grava "duração estimada: 5 dias · responsável:
# Ana", e sem esse delimitador o valor de um campo anterior engolia a duracao inteira
# quando o editor do ProjectAdm juntava as linhas (sem o '·').
ROTULOS_CAMPO = (r"probabilidade|urg[eê]ncia|impacto|prioridade|resposta|a[cç][aã]o|"
                 r"dono|respons[aá]vel|depende|pacote|valor|quando|"
                 r"dura[cç][aã]o(?:\s+estimada)?|(?:estimated\s+)?duration|"
                 r"probability|likelihood|urgency|impact|priority|response|action|"
                 r"owner|responsible|assignee|depends|package|value|when")

# Grupos de parte interessada e niveis de engajamento.
GRUPO_PARTE = {"client": "cliente", "customer": "cliente", "team": "equipe",
               "others": "demais", "other": "demais"}
ENGAJAMENTO = {"unknown": "desconhecido", "resistant": "resistente",
               "neutral": "neutro", "supportive": "apoiador", "supporter": "apoiador",
               "leading": "lider", "leader": "lider"}

# ─────────────────────────────────────────────────────────────────────────────
# ROTULOS QUE O CURSO ESCREVE NO CARTAO (nao a IA)
#
# As tabelas acima ensinam o parser a ler a RESPOSTA DA IA. Estas ensinam a ler o
# CARTAO — que quem escreveu foi o proprio curso, no idioma do pacote. E' uma armadilha
# diferente e pior: o Passo 1 grava "Role:" no pacote ingles, e todo mundo que le o
# cartao depois (o Registro das partes interessadas, a auditoria do Passo 6) procurava
# "Papel:" — nao achava nada, nao dava erro, e a planilha saia com o nome da parte e
# mais nada (Eduardo, quadro 324/FIRE, 06/08/2026).
#
# Valor = alternativa de regex, PORTUGUES PRIMEIRO (a forma canonica). Quem consome
# usa `_campo_linha(txt, ROTULOS_PARTE["papel"])` — nunca o literal.
# ─────────────────────────────────────────────────────────────────────────────
ROTULOS_PARTE = {
    "papel": r"papel|role",
    "espera": (r"o que espera do projeto|o que espera|"
               r"what they expect from the project|what they expect|expects"),
    # O ENDERECO DE E-MAIL da pessoa (2026-08-07). Entrou com o Passo 7 novo, que manda
    # a cada dono a lista de atividades dele: o endereco tinha de morar em algum lugar, e
    # o lugar e' o quadro — a mesma fonte de todo o resto. Ele tambem preenche a coluna
    # "e-mail" do Registro das partes interessadas, que nascia sempre vazia.
    # Aceita as tres grafias porque o cartao pode ter sido escrito pelo curso, pela IA ou
    # pelo proprio aluno: "e-mail", "email", "e-mail address".
    "email": r"e-?mail(?:\s+address)?",
    "poder": r"poder|power",
    "interesse": r"interesse|interest",
    "atual": r"engajamento atual|current engagement",
    "desejado": r"desejado|desired",
    "estrategia": r"estrat[ée]gia|strategy",
    "cadencia": r"cad[êe]ncia|cadence",
}

# O cabecalho que o Passo 6 grava no cartao da parte — o marcador de "tem plano de
# engajamento". Nos dois idiomas, pelo mesmo motivo do `_MARCAS_PLANO` do Passo 6:
# quadro montado por um pacote e aberto pelo outro tem de continuar sendo lido.
PLANO_ENGAJAMENTO = r"plano de engajamento|engagement plan"

# Tipos de custo do orcamento.
TIPO_CUSTO = {"people": "pessoas", "staff": "pessoas", "purchase": "compra",
              "service": "servico", "license": "licenca", "reserve": "reserva",
              "contingency": "reserva"}

# Cabecalhos do OKR e do Key Result, dentro do proprio texto do cartao 1.2.
OBJETIVO_RE = r"(?:objetivo|objective)"
KR_RE = r"(?:kr|key\s*result)"


def campo(nome):
    """O nome canonico (portugues) de um campo escrito em qualquer um dos idiomas."""
    return CAMPOS.get(nome, nome)


def secao(nome):
    """O nome canonico de uma secao. Recebe e devolve texto ja' sem acento."""
    return SECOES.get(nome.lower(), nome)


def valor(nome, tabela):
    """O valor canonico numa das tabelas de valor (grupo, engajamento, custo)."""
    return tabela.get((nome or "").strip().lower(), nome)
