#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Oct 14 09:36:40 2024

@author: ojacques
"""
"""
https://dadosabertos.tse.jus.br/vi/dataset/resultados-2024-boletim-de-urna
"""

'''
O pacote asn1tools é uma biblioteca Python amplamente utilizada para 
codificar (encode), decodificar (decode) e manipular dados estruturados 
usando a sintaxe ASN.1 (Abstract Syntax Notation One).
'''
import asn1tools

#Outra biblioteca Python muito popular para lidar com ASN.1
#import asn1crypto

'''
Pacote com o algoritmos ed25519 para garantir a autenticidade e a integridade
de dados (provar que quem enviou a informação é realmente quem diz ser e que 
o arquivo não foi alterado).
O algoritmo ed25519 faz parte da biblioteca ECPy - biblioteca de código aberto 
para a linguagem Python com foco estrito em Criptografia de Curva Elíptica (ECC).
Ver curva EDSA - Edwards-curve Signature Algorithm
'''
#import ed25519


def imprBU(bu):
    # ---------------------------------------------------------
    # Identificação da seção
    # ---------------------------------------------------------
    identificacao = bu["identificacaoSecao"]
    municipio = identificacao["municipioZona"]["municipio"]
    zona = identificacao["municipioZona"]["zona"]
    secao = identificacao["secao"]

    print("=" * 70)
    print("IDENTIFICAÇÃO DA SEÇÃO")
    print("=" * 70)
    print(f"Município:       {municipio}")
    print(f"Zona Eleitoral:  {zona}")
    print(f"Seção Eleitoral: {secao}")
    print()
    qtdEleitoresCompareceram=bu['qtdEleitoresCompareceram']
    detalhes = bu['detalhamentoComparecimento']
    qtdEleitoresCompareceramSemBiometria=detalhes['qtdEleitoresCompareceramSemBiometria']
    qtdEleitoresHabilitadosPorBiometria=detalhes['qtdEleitoresHabilitadosPorBiometria']
    qtdEleitoresHabilitadosPorBiografia=detalhes['qtdEleitoresHabilitadosPorBiografia']
         
    # ---------------------------------------------------------
    # Localiza as eleições
    # Neste caso, só tem uma, mas pode ser que haja mais de uma
    # Verificar que tem a chave 'idEleicao' : 619
    # ---------------------------------------------------------
    resultados_eleicoes = bu["resultadosVotacaoPorEleicao"]  
    
    qtdEleitoresAptos=resultados_eleicoes[0]['qtdEleitoresAptos']
    qtdEleitoresAptosSecao=resultados_eleicoes[0]['qtdEleitoresAptosSecao']
    qtdEleitoresAptosTTE = resultados_eleicoes[0]['qtdEleitoresAptosTTE']
    qtdEleitoresFaltosos = qtdEleitoresAptos - qtdEleitoresCompareceram  
    
    print("Eleitores Aptos: {qtdEleitoresAptos}")
   
    print(f"\t Originais da Seção: {qtdEleitoresAptosSecao}")
    print(f"\t Temporários na Seção:{qtdEleitoresAptosTTE}")

    print(f"Comparecimento: {qtdEleitoresCompareceram}")

    print(f"\t Habilitação biométrica: {qtdEleitoresHabilitadosPorBiometria}")
    print(f"\t Habilitação biográfica: {qtdEleitoresHabilitadosPorBiografia}")
    print(f"\t Habilitação sem biometria: {qtdEleitoresCompareceramSemBiometria}")
    print(f"Eleitores faltosos: {qtdEleitoresFaltosos}")
    
    # Mesmo tendo uma só eleição seguir o conceito
    for eleicao in resultados_eleicoes:
        for resultado in eleicao["resultadosVotacao"]:

            tipoCargo = resultado["tipoCargo"]
            votosCargo = resultado["totaisVotosCargo"]

            # =================================================
            # VEREADOR
            # =================================================
            if tipoCargo == "proporcional":

                print("=" * 70)
                print("VOTOS PARA VEREADOR")
                print("=" * 70)

                # Dicionário para agrupar votos por partido
                partidos = {}

                totalNominais = 0
                totalLegenda = 0
                totalBrancos = 0
                totalNulos = 0

                # ---------------------------------------------
                # Processa os votos
                # ---------------------------------------------
                for cargo in votosCargo:

                    votos = cargo["votosVotaveis"]

                    for voto in votos:

                        tipoVoto = voto["tipoVoto"]
                        quantidade = voto["quantidadeVotos"]

                        # Voto nominal
                        if tipoVoto == "nominal":
                            partido = voto["identificacaoVotavel"]["partido"]
                            vereador = voto["identificacaoVotavel"]["codigo"]

                            totalNominais += quantidade

                            if partido not in partidos:
                                partidos[partido] = {
                                    "vereadores": {},
                                    "legenda": 0
                                }

                            partidos[partido]["vereadores"][vereador] = (
                                partidos[partido]["vereadores"].get(vereador, 0)
                                + quantidade
                            )

                        # Voto de legenda
                        elif tipoVoto == "legenda":
                            partido = voto["identificacaoVotavel"]["partido"]

                            totalLegenda += quantidade

                            if partido not in partidos:
                                partidos[partido] = {
                                    "vereadores": {},
                                    "legenda": 0
                                }

                            partidos[partido]["legenda"] += quantidade

                        # Voto branco
                        elif tipoVoto == "branco":
                            totalBrancos += quantidade

                        # Voto nulo
                        elif tipoVoto == "nulo":
                            totalNulos += quantidade

                # ---------------------------------------------
                # Imprime os partidos
                # ---------------------------------------------
                for partido in sorted(partidos):

                    dadosPartido = partidos[partido]

                    print()
                    print(f"Partido: {partido}")
                    print("-" * 50)

                    totalPartido = 0

                    # Vereadores
                    for vereador, votos in sorted(
                        dadosPartido["vereadores"].items()
                    ):
                        print(
                            f"  Vereador {vereador}: "
                            f"{votos} voto(s)"
                        )

                        totalPartido += votos

                    # Legenda
                    legenda = dadosPartido["legenda"]

                    print(f"  Legenda: {legenda} voto(s)")

                    totalPartido += legenda

                    # Total do partido
                    print(f"  Total do Partido {partido}: {totalPartido}")

                # ---------------------------------------------
                # Totais para vereador
                # ---------------------------------------------
                print()
                print("-" * 70)
                print("TOTAIS - VEREADOR")
                print("-" * 70)

                print(f"Total de votos Nominais: {totalNominais}")
                print(f"Total de votos de Legenda: {totalLegenda}")
                print(f"Brancos: {totalBrancos}")
                print(f"Nulos: {totalNulos}")

                print()

            # =================================================
            # PREFEITO
            # =================================================
            elif tipoCargo == "majoritario":

                print("=" * 70)
                print("VOTOS PARA PREFEITO")
                print("=" * 70)

                totalNominais = 0
                totalBrancos = 0
                totalNulos = 0

                # ---------------------------------------------
                # Processa os votos
                # ---------------------------------------------
                for cargo in votosCargo:

                    votos = cargo["votosVotaveis"]

                    for voto in votos:

                        tipoVoto = voto["tipoVoto"]
                        quantidade = voto["quantidadeVotos"]

                        # Candidato
                        if tipoVoto == "nominal":
                            candidato = voto["identificacaoVotavel"]["codigo"]

                            print(
                                f"Candidato {candidato}: "
                                f"{quantidade} voto(s)"
                            )

                            totalNominais += quantidade

                        # Branco
                        elif tipoVoto == "branco":
                            totalBrancos += quantidade

                        # Nulo
                        elif tipoVoto == "nulo":
                            totalNulos += quantidade

                # ---------------------------------------------
                # Totais para prefeito
                # ---------------------------------------------
                print()
                print("-" * 70)
                print("TOTAIS - PREFEITO")
                print("-" * 70)

                print(f"Total de votos Nominais: {totalNominais}")
                print(f"Brancos: {totalBrancos}")
                print(f"Nulos: {totalNulos}")

                print()


# =============================================================
# EXECUÇÃO
# =============================================================
def main():
    
#==============================================================================
# SEGUINDO AS INSTRUÇÕES DO README.pdf
#==============================================================================

    asn1_path = '../formato-arquivos-bu-rdv-ass-digital-v2/spec/bu.asn1'
    bu_path = 'o00452ms9073500180108-bu.dat'

#1. crie um objeto informando o caminho para o arquivo de especificação 
# do formato do BU (bu.asn1):
    conv = asn1tools.compile_files(asn1_path, codec="ber")
    
#2. leia o conteúdo do arquivo de BU:
    with open(bu_path, "rb") as bu:
        envelope_encoded = bytearray(bu.read())

#3. converta o conteúdo do envelope (essa operação cria um dicionário com 
# a estrutura descrita no diagrama do BU):   
    envelope_decoded = conv.decode("EntidadeEnvelopeGenerico",envelope_encoded)

#4. o conteúdo do BU está no campo "conteudo" do dicionário. Converta esse conteúdo:
    bu_encoded = envelope_decoded["conteudo"]
    bu_decoded = conv.decode("EntidadeBoletimUrna", bu_encoded)

#5. A informação do BU está agora disponível na variável bu_decoded para ser 
# processada. No exemplo fornecido, o conteúdo é impresso para o console.

    imprBU(bu_decoded)


if __name__ == '__main__':
     main()




# PARA ATRAPALHAR MENOS COM DICIONÁRIOS
# Mostra o dicionário em cores para entendimento
# from rich import print
# print(bu_decoded)
# Melhor ainda
#from rich.pretty import pprint
#pprint(dados)

# bu_decoded['resultadosVotacaoPorEleicao'][0]['resultadosVotacao'][0]['totaisVotosCargo'][0]['votosVotaveis'][0]['quantidadeVotos']
# bu_decoded['resultadosVotacaoPorEleicao'][0]['resultadosVotacao'][0]['totaisVotosCargo'][0]['votosVotaveis'][0]['identificacaoVotavel']['partido']
# bu_decoded['resultadosVotacaoPorEleicao'][0]['resultadosVotacao'][0]['totaisVotosCargo'][0]['votosVotaveis'][0]['codigo']

# vereador
# bu_decoded['resultadosVotacaoPorEleicao'][0]['resultadosVotacao'][0]['totaisVotosCargo'][0]['codigoCargo'][1]
# prefeito
# bu_decoded['resultadosVotacaoPorEleicao'][0]['resultadosVotacao'][1]['totaisVotosCargo'][0]['codigoCargo'][1]

# votos prefeito
# bu_decoded['resultadosVotacaoPorEleicao'][0]['resultadosVotacao'][1]['totaisVotosCargo'][0]['votosVotaveis']