import yaml
import logging
from pathlib import Path
from typing import List, Dict, Any, Union
from xulcan.blueprint.schema import AgentBlueprint
from xulcan.protocol.tools import ToolDefinition
from xulcan.system.naming import random_agent_name

logger = logging.getLogger("xulcan.blueprint.loader")

class BlueprintLoader:
    
    # =========================================================
    # 1. EL NÚCLEO LÓGICO (Solo maneja diccionarios de Python)
    # =========================================================
    @staticmethod
    def from_dict(data: Dict[str, Any]) -> AgentBlueprint:
        """Hidrata un Blueprint desde un diccionario crudo, aplicando lógica de negocio."""
        # 🎲 MAGIA: Si no trae nombre, lo bautizamos al vuelo
        if not data.get("name"):
            epic_name = random_agent_name()
            data["name"] = epic_name
            if not data.get("id"):
                data["id"] = f"agent-{epic_name.lower().replace(' ', '-')}"
                
            logger.info(f"✨ Nuevo Agente Forjado: {epic_name} ({data['id']})")
            
        return AgentBlueprint.model_validate(data)

    # =========================================================
    # 2. LOS ADAPTADORES DE FORMATO (YAML Strings)
    # =========================================================
    @classmethod
    def from_yaml_string(cls, yaml_content: str) -> AgentBlueprint:
        """Carga un Blueprint directamente desde un texto en formato YAML (Ej: desde una API HTTP)."""
        data = yaml.safe_load(yaml_content)
        if not data:
            raise ValueError("El YAML proporcionado está vacío o es inválido.")
        return cls.from_dict(data)

    # =========================================================
    # 3. LOS ADAPTADORES DE I/O (Disco Duro)
    # =========================================================
    @classmethod
    def from_file(cls, file_path: Union[str, Path]) -> AgentBlueprint:
        """Carga un Blueprint leyendo un archivo del disco."""
        path = Path(file_path)
        if not path.exists():
            raise FileNotFoundError(f"No se encontró el Blueprint en: {path}")
            
        with open(path, "r", encoding="utf-8") as f:
            yaml_content = f.read()
            
        # Reutilizamos la lógica del string
        return cls.from_yaml_string(yaml_content)

    # (Puedes aplicar este mismo patrón exacto a load_tools)