"""
Project Together — powered by AI: o seu PACOTE esta' inteiro? (conferencia + conserto)

O QUE ISTO CONFERE — e por que nao e' a mesma coisa que o resto do painel
    O painel (verificar_projeto.py) pergunta "como esta' o meu PROJETO?". Aqui a
    pergunta e' anterior: "as pecas que o curso usa para achar o seu projeto estao no
    lugar?". Sao duas conferencias:

      · O SEU .env — UMA linha por dado. Duas linhas para o mesmo dado (PROJETO ao lado
        de PROJECT, IDIOMA ao lado de LANGUAGE) e' o pior estado possivel: voce edita
        uma e o curso le a outra, e nada avisa.

      · O SEU QUADRO — uma lista por papel, no idioma do seu pacote. Duas listas para o
        mesmo papel (uma em cada lingua) significam que metade do curso escreve numa e
        metade le a outra.

POR QUE ELE EXISTE (quadro 324, 06 e 07/08/2026)
    `garantir_listas` procurava as listas PELO NOME no idioma da execucao; nao achando,
    CRIAVA. Uma execucao que caiu no portugues — porque a variavel de ambiente LANGUAGE
    do sistema respondeu antes do .env — encontrou um quadro em ingles, nao reconheceu
    nenhuma lista e montou as 8 de novo, vazias, ao lado das que tinham 157 cartoes.
    Tres vezes.

    As portas ja' estao fechadas no codigo: o idioma agora vem do .env (idioma.py), quem
    procura lista conhece os dois idiomas (quadro.nomes_conhecidos) e a atualizacao nao
    acrescenta mais chave repetida (update.py). Este modulo e' a rede embaixo: ele diz o
    que ficou torto ANTES das correcoes chegarem, e conserta.

NADA AQUI ESCREVE SOZINHO. `conferir()` so' LE. `consertar()` roda com o seu "sim" (ou
com --conformidade, para rodar sem ninguem na frente).
"""
import quadro
import env as envmod
import idioma
from env import cfg, save_cfg
from idioma import T, Tf

LACUNA, ATENCAO = "lacuna", "atencao"

# As chaves que o curso NAO pode adivinhar: sem elas nao ha' o que abrir.
_ESSENCIAIS = ("PROJECTADM_TOKEN", "BOARD_ID")


def _achado(nivel, tipo, resumo, detalhe=(), dados=None):
    return {"nivel": nivel, "tipo": tipo, "resumo": resumo,
            "detalhe": list(detalhe), "dados": dados}


def _conferir_env(c):
    """O arquivo .env: uma linha por dado, e os dados essenciais preenchidos."""
    achados = []

    dups = envmod.duplicadas()
    if dups:
        detalhe = []
        for d in dups:
            if d["motivo"] == "repetida":
                detalhe.append(Tf('{0} aparece duas vezes; vale "{1}" (a última linha).',
                                  d["chave"], d["valor"]))
            else:
                detalhe.append(Tf('{0} e {1} são o mesmo dado; fica "{2}" e sai "{3}".',
                                  d["sobra"], d["chave"], d["valor"], d["descartado"]))
        achados.append(_achado(
            ATENCAO, "env_duplicadas",
            Tf("{0} dado(s) escrito(s) em duas linhas do .env — você edita uma e o curso "
               "lê a outra.", len(dups)),
            detalhe, dups))

    for chave in _ESSENCIAIS:
        if envmod.e_placeholder(c.get(chave)):
            achados.append(_achado(
                LACUNA, "env_essencial",
                Tf("{0} ainda não está preenchido no .env — sem ele o curso não abre o "
                   "seu quadro.", chave)))
    return achados


def _conferir_idioma(c, listas, abordagem):
    """O idioma: quem manda e' o seu .env — e o quadro tem de concordar com ele."""
    achados = []
    origem = idioma.origem()
    if origem in ("LANGUAGE", "IDIOMA", "TOGETHER_LANGUAGE"):
        achados.append(_achado(
            ATENCAO, "idioma_ambiente",
            Tf("O idioma desta execução ({0}) veio da variável de ambiente {1}, não do seu "
               ".env. Apague essa variável para o seu .env voltar a mandar.",
               idioma.lang(), origem)))

    do_quadro = quadro.idioma_do_quadro(listas, abordagem)
    if do_quadro and do_quadro != idioma.lang():
        achados.append(_achado(
            ATENCAO, "idioma_quadro",
            Tf("O seu quadro foi montado em {0} e este pacote está rodando em {1}.",
               do_quadro, idioma.lang()),
            [T("Ao montar as listas, o curso renomeia as suas listas para o idioma do "
               "pacote — o id e os cartões são preservados."),
             Tf("Se o certo era continuar em {0}, conserte o .env (LANGUAGE={0}) antes de "
                "rodar qualquer passo.", do_quadro)],
            do_quadro))
    return achados


def _conferir_listas(c, listas, abordagem):
    """O quadro: uma lista por papel, e o .env apontando para elas."""
    achados = []
    idx = quadro.indice_de_nomes(abordagem)
    por_chave = {}
    for l in listas:
        chave = idx.get((l.get("nome") or "").strip().lower())
        if chave:
            por_chave.setdefault(chave, []).append(l)

    duplicadas = {k: v for k, v in por_chave.items() if len(v) > 1}
    if duplicadas:
        detalhe = []
        for chave, ls in duplicadas.items():
            nomes = " · ".join(f'"{(l.get("nome") or "").strip()}" '
                               + Tf("({0} cartão(ões))", l.get("total_cartoes", "?"))
                               for l in ls)
            detalhe.append(f"{chave}: {nomes}")
        achados.append(_achado(
            ATENCAO, "listas_duplicadas",
            Tf("{0} papel(éis) com mais de uma lista no quadro — quase sempre a mesma "
               "lista escrita nos dois idiomas.", len(duplicadas)),
            detalhe + [T("Ao montar as listas, o curso fica com a que tem os seus cartões "
                         "e apaga a duplicada VAZIA. Uma duplicada COM cartões é "
                         "preservada: mova os cartões e apague-a você mesmo.")],
            list(duplicadas)))

    # LIST_* apontando para uma lista que nao existe mais neste quadro.
    ids_do_quadro = {str(l["id"]) for l in listas}
    perdidos = [chave for chave, _t in quadro.listas_do_quadro(abordagem)
                if str(c.get(f"LIST_{chave}") or "").strip()
                and str(c.get(f"LIST_{chave}")).strip() not in ids_do_quadro]
    if perdidos:
        achados.append(_achado(
            ATENCAO, "listas_perdidas",
            Tf("{0} chave(s) LIST_* do .env apontam para uma lista que não está mais neste "
               "quadro: {1}.", len(perdidos), ", ".join(perdidos)),
            [T("O curso reaponta sozinho ao montar as listas.")],
            perdidos))
    return achados


def conferir(c=None, listas=None, abordagem=None):
    """Todas as conferencias. So' LE — nem o .env, nem o quadro sao tocados aqui.

    `listas` e `abordagem` sao opcionais: sem eles, so' as conferencias do .env rodam
    (util antes de haver quadro)."""
    c = c or cfg()
    achados = _conferir_env(c)
    if listas is not None:
        achados += _conferir_idioma(c, listas, abordagem)
        achados += _conferir_listas(c, listas, abordagem)
    return achados


def consertavel(achados):
    """Os achados que ESTE modulo conserta (os outros o curso conserta sozinho, ao montar
    as listas, ou dependem de uma decisao que nao e' nossa)."""
    return [a for a in achados if a["tipo"] in ("env_duplicadas", "idioma_quadro")]


def relatar(achados):
    """As linhas do painel."""
    if not achados:
        return [T("   ✅ Pacote conforme: uma linha por dado no .env e uma lista por papel "
                  "no quadro.")]
    L = []
    for a in achados:
        marca = "✗" if a["nivel"] == LACUNA else "•"
        L.append(f"   {marca} {a['resumo']}")
        L += [f"      - {d}" for d in a["detalhe"]]
    return L


def consertar(achados, log=print):
    """Aplica o que da' para aplicar. Devolve quantos achados foram consertados."""
    feitos = 0
    for a in consertavel(achados):
        if a["tipo"] == "env_duplicadas":
            n = envmod.consolidar(a["dados"])
            if n:
                log(Tf("   [OK] .env: {0} linha(s) repetida(s) removida(s) — um dado, uma "
                       "linha.", n))
                feitos += 1
        elif a["tipo"] == "idioma_quadro":
            save_cfg({"LANGUAGE": a["dados"]})
            log(Tf("   [OK] .env: LANGUAGE={0} (o idioma em que o seu quadro foi montado). "
                   "Rode este painel de novo para o curso inteiro sair nesse idioma.",
                   a["dados"]))
            feitos += 1
    return feitos


def main(argv=None):
    """Rodar sozinho: `py conformidade.py` (confere) · `--consertar` (confere e conserta)."""
    import sys
    from pa_client import list_lists
    from runner import header
    argv = list(sys.argv[1:] if argv is None else argv)
    c = cfg()
    header(T("Project Together — Conformidade do pacote"))
    print()
    listas = list_lists() if not envmod.e_placeholder(c.get("BOARD_ID")) else None
    abordagem = quadro.abordagem_do_env()
    achados = conferir(c, listas, abordagem)
    for linha in relatar(achados):
        print(linha)
    if consertavel(achados) and "--consertar" in argv:
        print()
        consertar(achados)
    elif consertavel(achados):
        print()
        print(T("   Rode com --consertar para eu arrumar o que dá para arrumar daqui."))


if __name__ == "__main__":
    main()
