"""
Agent Configuration Loading

Loads agent configurations from groknroll.json and .groknroll/agent/ directories.
"""

import json
from dataclasses import dataclass
from pathlib import Path
from typing import Optional

import yaml


@dataclass
class AgentConfigData:
    """Agent configuration data"""

    name: str
    description: str
    capabilities: list[str]
    model: str = "gpt-4o-mini"
    max_cost: float = 5.0
    timeout: int = 300
    temperature: Optional[float] = None
    max_steps: Optional[int] = None
    permissions: Optional[dict[str, str]] = None
    system_prompt: Optional[str] = None


class AgentConfigLoader:
    """
    Agent Configuration Loader

    Loads agent configurations from:
    1. groknroll.json (agent section)
    2. .groknroll/agent/<name>.md (custom agent definitions)
    """

    def __init__(self, project_path: Path):
        """
        Initialize loader

        Args:
            project_path: Project root path
        """
        self.project_path = project_path
        self.groknroll_config_path = project_path / "groknroll.json"
        self.agent_dir = project_path / ".groknroll" / "agent"

    def load_from_json(self) -> dict[str, AgentConfigData]:
        """
        Load agent configurations from groknroll.json

        Returns:
            Dict of agent name to configuration
        """
        if not self.groknroll_config_path.exists():
            return {}

        try:
            with open(self.groknroll_config_path) as f:
                config = json.load(f)

            agents = config.get("agent", {})
            result = {}

            for name, agent_config in agents.items():
                result[name] = AgentConfigData(
                    name=name,
                    description=agent_config.get("description", f"{name} agent"),
                    capabilities=agent_config.get("capabilities", []),
                    model=agent_config.get("model", "gpt-4o-mini"),
                    max_cost=agent_config.get("max_cost", 5.0),
                    timeout=agent_config.get("timeout", 300),
                    temperature=agent_config.get("temperature"),
                    max_steps=agent_config.get("max_steps"),
                    permissions=agent_config.get("permission"),
                )

            return result

        except (json.JSONDecodeError, KeyError) as e:
            raise ValueError(f"Invalid groknroll.json format: {e}")

    def load_from_markdown(self, agent_name: str) -> Optional[AgentConfigData]:
        """
        Load custom agent from .groknroll/agent/<name>.md

        Args:
            agent_name: Agent name

        Returns:
            AgentConfigData or None if not found
        """
        agent_file = self.agent_dir / f"{agent_name}.md"

        if not agent_file.exists():
            return None

        try:
            content = agent_file.read_text()

            # Parse YAML frontmatter
            if not content.startswith("---\n"):
                raise ValueError("Agent file must start with YAML frontmatter")

            parts = content.split("---\n", 2)
            if len(parts) < 3:
                raise ValueError("Invalid frontmatter format")

            frontmatter = yaml.safe_load(parts[1])
            system_prompt = parts[2].strip()

            # Extract configuration
            return AgentConfigData(
                name=frontmatter.get("name", agent_name),
                description=frontmatter.get("description", f"{agent_name} agent"),
                capabilities=frontmatter.get("capabilities", []),
                model=frontmatter.get("model", "gpt-4o-mini"),
                max_cost=frontmatter.get("max_cost", 5.0),
                timeout=frontmatter.get("timeout", 300),
                temperature=frontmatter.get("temperature"),
                max_steps=frontmatter.get("max_steps"),
                permissions=frontmatter.get("permission"),
                system_prompt=system_prompt if system_prompt else None,
            )

        except (yaml.YAMLError, ValueError) as e:
            raise ValueError(f"Invalid agent file format for {agent_name}: {e}")

    def load_all_custom_agents(self) -> dict[str, AgentConfigData]:
        """
        Load all custom agents from .groknroll/agent/ directory

        Returns:
            Dict of agent name to configuration
        """
        if not self.agent_dir.exists():
            return {}

        result = {}

        for agent_file in self.agent_dir.glob("*.md"):
            agent_name = agent_file.stem
            try:
                agent_config = self.load_from_markdown(agent_name)
                if agent_config:
                    result[agent_name] = agent_config
            except ValueError:
                # Skip invalid agent files
                continue

        return result

    def load_all(self) -> dict[str, AgentConfigData]:
        """
        Load all agent configurations

        Priority: groknroll.json > .groknroll/agent/<name>.md

        Returns:
            Dict of agent name to configuration
        """
        # Start with custom agents from .groknroll/agent/
        configs = self.load_all_custom_agents()

        # Override with groknroll.json configs
        json_configs = self.load_from_json()
        configs.update(json_configs)

        return configs

    def validate_config(self, config: AgentConfigData) -> bool:
        """
        Validate agent configuration

        Args:
            config: Agent configuration

        Returns:
            True if valid

        Raises:
            ValueError: If configuration is invalid
        """
        # Validate name
        if not config.name or not (1 <= len(config.name) <= 64):
            raise ValueError("Agent name must be 1-64 characters")

        if not config.name.replace("-", "").replace("_", "").isalnum():
            raise ValueError("Agent name must contain only alphanumeric, hyphens, and underscores")

        # Validate description
        if not config.description or not (1 <= len(config.description) <= 1024):
            raise ValueError("Agent description must be 1-1024 characters")

        # Validate capabilities
        valid_capabilities = [
            "read_files",
            "write_files",
            "edit_files",
            "delete_files",
            "execute_bash",
            "git_operations",
            "analyze_code",
            "search_code",
        ]

        for cap in config.capabilities:
            if cap not in valid_capabilities:
                raise ValueError(f"Invalid capability: {cap}")

        # Validate numeric values
        if config.max_cost <= 0:
            raise ValueError("max_cost must be positive")

        if config.timeout <= 0:
            raise ValueError("timeout must be positive")

        if config.temperature is not None and not (0 <= config.temperature <= 2):
            raise ValueError("temperature must be between 0 and 2")

        if config.max_steps is not None and config.max_steps <= 0:
            raise ValueError("max_steps must be positive")

        return True


def load_agent_config(project_path: Path) -> dict[str, AgentConfigData]:
    """
    Convenience function to load all agent configurations

    Args:
        project_path: Project root path

    Returns:
        Dict of agent name to configuration
    """
    loader = AgentConfigLoader(project_path)
    return loader.load_all()
