"""Security sandbox and validators."""

import json
import re
from typing import Dict, Any, Set, Optional, Pattern


class ValidadorPayload:
    """Validador de payload para tareas."""
    
    def __init__(self, max_bytes: int = 1_000_000, tipos_permitidos: Optional[list] = None):
        self.max_bytes = max_bytes
        self.tipos_permitidos = tipos_permitidos or ["str", "dict", "list", "int", "float", "bool"]
    
    def validar(self, tarea: Any) -> bool:
        """Valida payload de tarea."""
        tipo = type(tarea).__name__
        if tipo not in self.tipos_permitidos:
            raise TypeError(f"Tipo no permitido: {tipo}")
        
        size = len(json.dumps(tarea, default=str).encode('utf-8'))
        if size > self.max_bytes:
            raise ValueError(f"Payload muy grande: {size}bytes")
        
        return True


class SandboxSeguridad:
    """Proporciona validación de seguridad para tareas (denylist/whitelist).
    
    Permite configurar:
    - Denylist: patrones prohibidos
    - Whitelist: patrones permitidos (si está habilitado)
    - Máximo de coincidencias permitidas
    """
    
    def __init__(self, habilitar_whitelist: bool = False):
        """
        Inicializa sandbox de seguridad.
        
        Args:
            habilitar_whitelist: Si True, usa whitelist instead de denylist
        """
        self.denylist: Set[str] = set()
        self.whitelist: Set[str] = set()
        self.denylist_regex: Set[Pattern[str]] = set()
        self.whitelist_regex: Set[Pattern[str]] = set()
        self.habilitar_whitelist = habilitar_whitelist
        self.lock = __import__('threading').Lock()
        self.contador_rechazos = 0
        
        # Denylist por defecto: comandos peligrosos
        self._inicializar_denylist_defecto()
    
    def _inicializar_denylist_defecto(self):
        """Agrega patrones peligrosos por defecto."""
        patrones_peligrosos = {
            "rm -rf",  # Borrado recursivo
            "del /s",  # Borrado en Windows
            ">NUL",    # Redirección peligrosa
            "exec(",   # Ejecución dinámica
            "__import__",  # Import dinámico
            "eval(",   # Evaluación dinámica
            "os.system",  # Llamadas al sistema
            "subprocess",  # Spawning procesos
        }
        self.denylist.update(patrones_peligrosos)
    
    def agregar_denylist(self, patron: str):
        """Agrega patrón a denylist."""
        with self.lock:
            self.denylist.add(patron.lower())

    def agregar_denylist_regex(self, patron: str):
        """Agrega patrón regex a denylist."""
        with self.lock:
            self.denylist_regex.add(re.compile(patron, re.IGNORECASE))
    
    def agregar_whitelist(self, patron: str):
        """Agrega patrón a whitelist."""
        with self.lock:
            self.whitelist.add(patron.lower())

    def agregar_whitelist_regex(self, patron: str):
        """Agrega patrón regex a whitelist."""
        with self.lock:
            self.whitelist_regex.add(re.compile(patron, re.IGNORECASE))
    
    def es_segura_tarea(self, tarea: str) -> bool:
        """Valida si la tarea es segura según políticas.
        
        Returns:
            True si la tarea es segura, False si es rechazada.
        """
        with self.lock:
            tarea_lower = str(tarea).lower()
            
            if self.habilitar_whitelist:
                # Modo whitelist: solo permitir patrones en whitelist
                match_text = any(patron in tarea_lower for patron in self.whitelist)
                match_regex = any(p.search(tarea_lower) for p in self.whitelist_regex)
                if not self.whitelist and not self.whitelist_regex:
                    es_segura = True
                else:
                    es_segura = match_text or match_regex
            else:
                # Modo denylist: rechazar si contiene patrón prohibido
                match_text = any(patron in tarea_lower for patron in self.denylist)
                match_regex = any(p.search(tarea_lower) for p in self.denylist_regex)
                es_segura = not (match_text or match_regex)
            
            if not es_segura:
                self.contador_rechazos += 1
            
            return es_segura
    
    def obtener_estadisticas_seguridad(self) -> Dict[str, Any]:
        """Obtiene estadísticas de validaciones de seguridad."""
        with self.lock:
            return {
                "tareas_rechazadas": self.contador_rechazos,
                "modo": "whitelist" if self.habilitar_whitelist else "denylist",
                "denylist_size": len(self.denylist),
                "whitelist_size": len(self.whitelist),
                "denylist_regex_size": len(self.denylist_regex),
                "whitelist_regex_size": len(self.whitelist_regex),
            }
    
    def limpiar_estadisticas(self):
        """Limpia contadores."""
        with self.lock:
            self.contador_rechazos = 0
