# -*- coding: utf-8 -*-
"""
DependenciesManager - Gerencia dependências externas (bibliotecas Python)

Responsável por:
- Verificar se módulos estão instalados
- Oferecer instalação automática via scripts .cmd/.bat
- Validação de dependências antes de processos
"""

import os
import sys

from qgis.PyQt.QtCore import QProcess
from qgis.PyQt.QtWidgets import QProgressDialog
from .QgisMessageUtil import QgisMessageUtil


class DependenciesManager:
    """Gerencia validação e instalação de dependências externas."""

    # Mapeamento de dependências: nome_requerimento -> (módulo_import, script_instalação)
    DEPENDENCIES = {
        "PyPDF2": {
            "import": "PyPDF2",
            "script": "install_pypdf2.bat",
            "description": "Unir/mesclar arquivos PDF",
            "pip": "PyPDF2",
        },
        "Pillow": {
            "import": "PIL",
            "script": "install_pillow.cmd",
            "description": "Processar e converter imagens (PNG)",
            "pip": "Pillow",
        },
    }

    @staticmethod
    def check_dependency(dependency_name: str) -> bool:
        """
        Verifica se uma dependência está instalada.

        Parameters
        ----------
        dependency_name : str
            Nome da dependência (ex: 'PyPDF2', 'Pillow')

        Returns
        -------
        bool
            True se instalada, False caso contrário

        Example
        -------
        if not DependenciesManager.check_dependency('PyPDF2'):
            print("PyPDF2 não está instalada")
        """
        if dependency_name not in DependenciesManager.DEPENDENCIES:
            return False

        dep_info = DependenciesManager.DEPENDENCIES[dependency_name]
        module_name = dep_info["import"]

        try:
            __import__(module_name)
            return True
        except ImportError:
            return False

    @staticmethod
    def get_dependency_info(dependency_name: str) -> dict:
        """
        Retorna informações sobre uma dependência.

        Returns
        -------
        dict
            Dicionário com 'import', 'script', 'description', 'pip'
        """
        return DependenciesManager.DEPENDENCIES.get(dependency_name, {})

    @staticmethod
    def get_install_script_path(dependency_name: str) -> str:
        """
        Retorna caminho completo do script de instalação.

        Parameters
        ----------
        dependency_name : str
            Nome da dependência (ex: 'PyPDF2', 'Pillow')

        Returns
        -------
        str
            Caminho do script .cmd/.bat (ou vazio se não encontrado)
        """
        if dependency_name not in DependenciesManager.DEPENDENCIES:
            return ""

        dep_info = DependenciesManager.DEPENDENCIES[dependency_name]
        script_name = dep_info["script"]

        # Procurar em caminhos padrão
        possible_paths = [
            # Relativo ao arquivo atual
            os.path.join(os.path.dirname(__file__), "..", "core", "lib", script_name),
            # Relativo ao projeto
            os.path.join(os.path.dirname(__file__), script_name),
        ]

        for path in possible_paths:
            abs_path = os.path.abspath(path)
            if os.path.exists(abs_path):
                return abs_path

        return ""

    @staticmethod
    def install_dependency(dependency_name: str) -> bool:
        """
        Instala a dependência usando o Python (`-m pip install --user ...`) de forma
        assíncrona via `QProcess` para evitar execução de scripts .bat e evitar
        uso de `shell=True`.

        Este método tenta iniciar o processo de instalação e retorna True se o
        processo foi iniciado com sucesso. A instalação é feita de forma
        não-bloqueante; para UI e feedback passe o parâmetro `iface` usando a
        função `install_dependency_gui` ou chame com `iface` quando disponível.
        """
        dep_info = DependenciesManager.get_dependency_info(dependency_name)
        if not dep_info:
            return False

        pip_name = dep_info.get("pip", dependency_name)

        python_exe = sys.executable or "python"

        # Use QProcess.startDetached como fallback (sem UI). Retorna True se o
        # processo foi iniciado corretamente.
        started = QProcess.startDetached(
            python_exe, ["-m", "pip", "install", "--user", pip_name]
        )
        if started:
            QgisMessageUtil.bar_info(None, f"Instalação iniciada: {pip_name}")
            return True

        return False

    @staticmethod
    def install_dependency_gui(dependency_name: str, iface) -> bool:
        """
        Instala a dependência mostrando um diálogo de progresso não-bloqueante.

        - `dependency_name`: nome da dependência (ex: 'PyPDF2')
        - `iface`: QgisInterface para parent do diálogo

        Retorna True se o processo de instalação foi iniciado, False caso contrário.
        """
        dep_info = DependenciesManager.get_dependency_info(dependency_name)
        if not dep_info:
            return False

        pip_name = dep_info.get("pip", dependency_name)
        python_exe = sys.executable or "python"

        parent = iface.mainWindow() if iface else None
        progress = QProgressDialog(
            f"Instalando dependência {pip_name}...", "Cancelar", 0, 0, parent
        )
        progress.setWindowTitle("Instalando dependências")
        progress.setAutoClose(True)
        progress.setModal(True)
        progress.show()

        proc = QProcess(parent)

        def _on_finished(exit_code, exit_status):
            progress.close()
            if exit_code == 0:
                QgisMessageUtil.bar_info(iface, f"Dependência instalada: {pip_name}")
            else:
                QgisMessageUtil.modal_error(
                    iface, f"Falha ao instalar {pip_name}. Código: {exit_code}"
                )

        def _on_error(err):
            progress.close()
            QgisMessageUtil.modal_error(iface, f"Erro ao iniciar instalação: {err}")

        proc.finished.connect(_on_finished)
        proc.errorOccurred.connect(_on_error)

        started = proc.start(python_exe, ["-m", "pip", "install", "--user", pip_name])
        if not started:
            progress.close()
            return False

        return True

    @staticmethod
    def validate_dependencies(required_dependencies: list) -> dict:
        """
        Valida múltiplas dependências de uma vez.

        Parameters
        ----------
        required_dependencies : list
            Lista de nomes de dependências (ex: ['PyPDF2', 'Pillow'])

        Returns
        -------
        dict
            {
                'all_present': bool,  # True se todas instaladas
                'missing': [],         # Dependências faltantes
                'present': []          # Dependências presentes
            }

        Example
        -------
        result = DependenciesManager.validate_dependencies(['PyPDF2', 'Pillow'])
        if not result['all_present']:
            print(f"Faltam: {result['missing']}")
        """
        missing = []
        present = []

        for dep_name in required_dependencies:
            if DependenciesManager.check_dependency(dep_name):
                present.append(dep_name)
            else:
                missing.append(dep_name)

        return {
            "all_present": len(missing) == 0,
            "missing": missing,
            "present": present,
        }
