import os
import time
from django.core.files import File
from django.core.management.base import BaseCommand
from diarios.models import DiarioOficial
from diarios.signals import update_document, delete_document
from django.db.models.signals import post_save, post_delete


class Command(BaseCommand):
    help = "Importa arquivos PDF de diários oficiais e associa aos objetos existentes no banco."

    def add_arguments(self, parser):
        parser.add_argument(
            "pasta",
            type=str,
            help="Caminho para a pasta contendo os arquivos PDF (nomes devem conter o número do diário)",
        )

    def handle(self, *args, **options):
        post_save.disconnect(update_document, sender=DiarioOficial)
        post_delete.disconnect(delete_document, sender=DiarioOficial)

        pasta = options["pasta"]
        if not os.path.isdir(pasta):
            self.stderr.write(
                self.style.ERROR(f"A pasta fornecida não existe: {pasta}")
            )
            return

        arquivos_pdf = [
            f
            for f in os.listdir(pasta)
            if f.lower().endswith(".pdf") and "Diário_Oficial_Eletrônico_nº_" in f
        ]

        if not arquivos_pdf:
            self.stdout.write(
                self.style.WARNING("Nenhum arquivo PDF válido encontrado na pasta.")
            )
            return

        total = len(arquivos_pdf)
        erros = []
        atualizados = []
        start_time = time.time()

        # Mapeia os números aos nomes de arquivos
        numero_para_arquivo = {
            f.replace("Diário_Oficial_Eletrônico_nº_", "")
            .replace(".pdf", "")
            .strip("_-"): f
            for f in arquivos_pdf
        }

        # Busca todos os objetos de uma vez
        diarios_existentes = DiarioOficial.objects.in_bulk(
            numero_para_arquivo.keys(), field_name="numero"
        )

        for idx, (numero, nome_arquivo) in enumerate(
            numero_para_arquivo.items(), start=1
        ):
            try:
                diario = diarios_existentes.get(numero)
                if not diario:
                    raise DiarioOficial.DoesNotExist()

                caminho_pdf = os.path.join(pasta, nome_arquivo)
                with open(caminho_pdf, "rb") as f:
                    diario.arquivo.save(nome_arquivo, File(f), save=True)

                atualizados.append(diario.pk)
                elapsed = time.time() - start_time
                remaining = (elapsed / idx) * (total - idx)
                self.stdout.write(
                    f"[{idx}/{total}] Atualizado: {nome_arquivo} | Estimativa restante: {remaining:.1f}s"
                )

            except DiarioOficial.DoesNotExist:
                msg = f"Não encontrado no banco: {nome_arquivo}"
                erros.append(msg)
                self.stderr.write(self.style.WARNING(msg))

            except Exception as e:
                msg = f"Erro ao processar {nome_arquivo}: {str(e)}"
                erros.append(msg)
                self.stderr.write(self.style.ERROR(msg))

        self.stdout.write(
            self.style.SUCCESS(f"{len(atualizados)} arquivos importados com sucesso.")
        )
        self.stdout.write(self.style.WARNING(f"{len(erros)} arquivos com erro."))

        if erros:
            caminho_log = os.path.join(pasta, "erros_importacao.txt")
            with open(caminho_log, "w", encoding="utf-8") as erro_file:
                for linha in erros:
                    erro_file.write(f"{linha}\n")
            self.stdout.write(
                self.style.WARNING(f"Erros registrados em: {caminho_log}")
            )

        post_save.connect(update_document, sender=DiarioOficial)
        post_delete.connect(delete_document, sender=DiarioOficial)
