"""
Módulo para gestión segura de configuración basada en variables de entorno.
Toda la configuración se obtiene desde archivos .env

Author: Json Rivera
Date: 2025-10-09
Version: 0.0.3
"""

import os
from typing import Any, Dict, List, Optional, Tuple

from dotenv import load_dotenv


class ConfigError(Exception):
    """Excepción personalizada para errores de configuración."""

    pass


class EnvConfigManager:
    """
    Gestor de configuración simple basado solo en variables de entorno.
    Una sola fuente de configuración desde archivos .env
    """

    def __init__(self, env_file: Optional[str] = None):
        """
        Inicializar el gestor de configuración.

        Args:
            env_file: Archivo .env específico a cargar (opcional)
        """
        self._load_environment(env_file)

    def _load_environment(self, env_file: Optional[str] = None) -> None:
        """Cargar variables de entorno desde archivos .env"""
        env_files_to_try: List[str] = []

        if env_file:
            env_files_to_try.append(env_file)

        # Buscar .env en directorio actual y directorio home
        current_dir: str = os.getcwd()
        home_dir: str = os.path.expanduser("~")

        # Orden de prioridad para archivos .env
        env_files_to_try.extend(
            [
                os.path.join(current_dir, ".env.local"),  # Específico del desarrollador
                os.path.join(
                    current_dir, ".env"
                ),  # General del proyecto (directorio actual)
                os.path.join(
                    home_dir, ".scavengr.env"
                ),  # Configuración global del usuario
            ]
        )

        loaded_files: List[str] = []
        for env_file_path in env_files_to_try:
            if os.path.exists(env_file_path):
                load_dotenv(env_file_path, override=True)
                loaded_files.append(env_file_path)
                # Debug: mostrar variables cargadas (sin valores sensibles)
                import logging

                logger = logging.getLogger(__name__)
                logger.debug(f"[DEBUG] Archivo .env cargado: {env_file_path}")

        if loaded_files:
            print(f"✅ Variables de entorno cargadas desde: {', '.join(loaded_files)}")
            import logging

            logger = logging.getLogger(__name__)
            logger.debug(f"[DEBUG] Total archivos .env procesados: {len(loaded_files)}")
        else:
            self._show_config_help()

    def _show_config_help(self) -> None:
        """Mostrar ayuda de configuración cuando no se encuentren archivos .env"""
        import platform

        is_windows: bool = platform.system() == "Windows"

        print("ℹ️  No se encontraron archivos de configuración .env")
        print()
        print("📋 Para configurar Scavengr, puede:")
        print("   1. Crear archivo .env en el directorio actual:")

        if is_windows:
            print("      echo DB_TYPE=postgresql > .env")
            print("      echo DB_HOST=localhost >> .env")
            print("      echo DB_NAME=mi_bd >> .env")
            print("      echo DB_USER=usuario >> .env")
            print("      echo DB_PASSWORD=contraseña >> .env")
        else:
            print("      echo 'DB_TYPE=postgresql' > .env")
            print("      echo 'DB_HOST=localhost' >> .env")
            print("      echo 'DB_NAME=mi_bd' >> .env")
            print("      echo 'DB_USER=usuario' >> .env")
            print("      echo 'DB_PASSWORD=contraseña' >> .env")

        print()
        print("   2. Crear configuración global en su directorio home:")
        home_config = os.path.join(os.path.expanduser("~"), ".scavengr.env")
        print(f"      {home_config}")
        print()
        print("   3. Usar variables de entorno del sistema:")

        if is_windows:
            print("      set DB_TYPE=postgresql")
            print("      set DB_HOST=localhost")
            print("      # ... etc")
        else:
            print("      export DB_TYPE=postgresql")
            print("      export DB_HOST=localhost")
            print("      # ... etc")

        print()
        print(
            "🆘 Para más detalles, visite: https://github.com/JasRockr/Scavengr#configuración"
        )
        print("   Usando variables del sistema como fallback...")

    def _validate_env_var(
        self, env_var: str, default: Any = None, required: bool = False
    ) -> Any:
        """
        Validar una variable de entorno.

        Args:
            env_var (str): Nombre de la variable de entorno.
            default (Any): Valor por defecto si no está configurada.
            required (bool): Indica si la variable es obligatoria.

        Returns:
            Any: Valor de la variable de entorno.

        Raises:
            ConfigError: Si la variable requerida no está configurada.
        """
        value = os.getenv(env_var, default)
        if required and not value and value != "":
            raise ConfigError(
                f"La variable de entorno requerida '{env_var}' no está configurada."
            )
        return value

    def get_db_config(self, env_prefix: str = "DB") -> Dict[str, Any]:
        """
        Obtener configuración de base de datos desde variables de entorno.

        Args:
            env_prefix: Prefijo para las variables (DB, PROD_DB, DEV_DB, etc.)

        Returns:
            Dict con configuración de base de datos
        """
        prefix: str = f"{env_prefix}_" if not env_prefix.endswith("_") else env_prefix

        # Variables requeridas
        required_vars: Dict[str, str] = {
            "type": f"{prefix}TYPE",
            "host": f"{prefix}HOST",
            "name": f"{prefix}NAME",
            "user": f"{prefix}USER",
            "password": f"{prefix}PASSWORD",
        }

        # Variables opcionales con valores por defecto
        optional_vars: Dict[str, Tuple[str, Optional[Any]]] = {
            "port": (f"{prefix}PORT", None),
            "driver": (f"{prefix}DRIVER", None),
        }

        config: Dict[str, Any] = {}

        # Validar y cargar variables requeridas
        for key, env_var in required_vars.items():
            config[key] = self._validate_env_var(env_var, required=True)

        # Validar el tipo de base de datos
        supported_db_types = ["postgresql", "mysql", "mssql"]
        if config["type"].lower() not in supported_db_types:
            raise ConfigError(
                f"Tipo de base de datos no soportado: {config['type']}. Tipos soportados: {', '.join(supported_db_types)}"
            )

        # Cargar variables opcionales con nombres simples
        for key, (env_var, default) in optional_vars.items():
            config[key] = self._validate_env_var(env_var, default=default)

        # Convertir puerto a entero si está presente
        if "port" in config and config["port"]:
            try:
                config["port"] = int(config["port"])
            except ValueError:
                # Si no se puede convertir, usar puertos por defecto según el tipo
                default_ports: Dict[str, int] = {
                    "postgresql": 5432,
                    "mysql": 3306,
                    "mssql": 1433,
                }
                config["port"] = default_ports.get(config["type"].lower(), None)

        return config

    def get_generation_config(self) -> Dict[str, Any]:
        """Obtener configuración para generación de diccionarios."""
        return {
            "source_system": {
                "name": os.getenv("SOURCE_SYSTEM_NAME", "Sistema de Base de Datos"),
                "version": os.getenv("SOURCE_SYSTEM_VERSION", "1.0"),
                "environment": os.getenv("SOURCE_ENVIRONMENT", "production"),
            },
            "file_prefix": os.getenv("OUTPUT_FILE_PREFIX", "diccionario_datos"),
        }

    def get_logging_config(self) -> Dict[str, Any]:
        """Obtener configuración básica de logging (mantenido por compatibilidad)."""
        return {"level": "INFO", "debug_mode": False}

    def get_security_config(self) -> Dict[str, Any]:
        """Obtener configuración básica de seguridad (mantenido por compatibilidad)."""
        return {"connection_timeout": 30, "max_retries": 3}

    def get_advanced_config(self) -> Dict[str, Any]:
        """Obtener configuración básica (mantenido por compatibilidad)."""
        return {}

    def get_all_config(self) -> Dict[str, Any]:
        """Obtener toda la configuración consolidada."""
        return {
            "database": self.get_db_config(),
            "generation": self.get_generation_config(),
            "logging": self.get_logging_config(),
            "security": self.get_security_config(),
            "advanced": self.get_advanced_config(),
        }

    def validate_config(self) -> Dict[str, Any]:
        """
        Validar configuración esencial.

        Returns:
            Dict con resultado de validación
        """
        issues: List[str] = []
        warnings: List[str] = []

        try:
            db_config: Dict[str, Any] = self.get_db_config()

            # Contraseñas inseguras comunes
            non_secured_pass: List[str] = ["", "password", "123456", "admin", "root"]

            #  == 'test_password' or db_config['password'] == ""
            # Validar configuración de BD
            if db_config["password"] in non_secured_pass:
                warnings.append("Parece estar usando una contraseña de prueba o vacía.")
                warnings.append(
                    "Considere usar contraseñas seguras en entornos de producción."
                )

        except ConfigError as e:
            issues.append(str(e))

        # Validar archivos .env
        if not os.path.exists(".env"):
            warnings.append("Archivo .env no encontrado, usando variables del sistema")

        return {"valid": len(issues) == 0, "issues": issues, "warnings": warnings}

    def _get_bool(self, env_var: str, default: bool) -> bool:
        """Obtener variable booleana de entorno."""
        value: Optional[str] = os.getenv(env_var)
        if value is None:
            return default
        return value.lower() in ("true", "1", "yes", "on")

    def _get_int(self, env_var: str, default: int) -> int:
        """Obtener variable entera de entorno."""
        value: Optional[str] = os.getenv(env_var)
        if value is None:
            return default
        try:
            return int(value)
        except ValueError:
            print(
                f"⚠️  Valor inválido para {env_var}: {value}, usando por defecto: {default}"
            )
            return default


# Funciones de utilidad para compatibilidad
def load_env_config(env_file: Optional[str] = None) -> EnvConfigManager:
    """
    Función de utilidad para crear gestor de configuración.

    Args:
        env_file: Archivo .env específico (opcional)

    Returns:
        EnvConfigManager configurado
    """
    return EnvConfigManager(env_file)


def get_database_config(env_prefix: str = "DB") -> Dict[str, Any]:
    """
    Función rápida para obtener configuración de BD.

    Args:
        env_prefix: Prefijo de variables (DB, PROD_DB, DEV_DB)

    Returns:
        Dict con configuración de base de datos
    """
    manager = EnvConfigManager()
    return manager.get_db_config(env_prefix)


if __name__ == "__main__":
    # Ejemplo de uso y validación
    print("🔧 Scavengr - Gestor de Configuración")
    print("=" * 50)

    manager: EnvConfigManager = EnvConfigManager()
    validation: Dict[str, Any] = manager.validate_config()

    if validation["valid"]:
        print("✅ Configuración válida")
        config: Dict[str, Any] = manager.get_all_config()
        print(
            f"📊 Configuración cargada para: {config['generation']['source_system']['name']}"
        )
    else:
        print("❌ Problemas de configuración:")
        for issue in validation["issues"]:
            print(f"   • {issue}")

    if validation["warnings"]:
        print("\n⚠️  Advertencias:")
        for warning in validation["warnings"]:
            print(f"   • {warning}")

    print("\n💡 Para configurar, copie .env.example a .env y edite las variables")
