"""Vibe package configuration parser and validator."""

import json
import os
from typing import Dict, Any, List
from pathlib import Path


# Default configuration format version
DEFAULT_CONFIG_VERSION = "1.0"


class VibePackageConfig:
    """Represents a vibe_package.json configuration."""
    
    def __init__(self, config_path: str):
        """
        Initialize VibePackageConfig.
        
        Args:
            config_path: Path to vibe_package.json file
        """
        self.config_path = Path(config_path)
        self.config = self._load_config()
        self._validate_config()
    
    def _load_config(self) -> Dict[str, Any]:
        """Load and parse the configuration file."""
        if not self.config_path.exists():
            raise FileNotFoundError(f"Configuration file not found: {self.config_path}")
        
        with open(self.config_path, 'r', encoding='utf-8') as f:
            return json.load(f)
    
    def _validate_config(self) -> None:
        """Validate the configuration structure."""
        # Check and validate version (optional, defaults to "1.0")
        config_version = self.config.get('version', DEFAULT_CONFIG_VERSION)
        if not isinstance(config_version, str):
            raise ValueError("'version' must be a string")
        # Future: check for unsupported versions and raise error or warning
        # Example: if config_version != DEFAULT_CONFIG_VERSION: ...

        # Check required fields
        if 'target_agents' not in self.config:
            raise ValueError("Missing required field: 'target_agents'")
        
        if 'dependencies' not in self.config:
            raise ValueError("Missing required field: 'dependencies'")
        
        # Validate target_agents
        target_agents = self.config['target_agents']
        if not isinstance(target_agents, list):
            raise ValueError("'target_agents' must be an array")

        if not target_agents:
            raise ValueError("'target_agents' cannot be empty")

        for agent in target_agents:
            if not isinstance(agent, str):
                raise ValueError(f"Invalid agent in 'target_agents': {agent}. Must be a string")
        
        # Validate dependencies
        dependencies = self.config['dependencies']
        if not isinstance(dependencies, dict):
            raise ValueError("'dependencies' must be an object")
        
        for dep_name, dep_config in dependencies.items():
            self._validate_dependency(dep_name, dep_config)
    
    def _validate_dependency(self, dep_name: str, dep_config: Dict[str, Any]) -> None:
        """Validate a single dependency configuration."""
        if 'type' not in dep_config:
            raise ValueError(f"Dependency '{dep_name}' missing required field: 'type'")
        
        dep_type = dep_config['type']
        
        if dep_type == 'SKILL':
            if 'git' not in dep_config:
                raise ValueError(f"SKILL dependency '{dep_name}' missing required field: 'git'")
            if 'git_tag' not in dep_config:
                raise ValueError(f"SKILL dependency '{dep_name}' missing required field: 'git_tag'")
        
        elif dep_type == 'SUBAGENT':
            if 'git' not in dep_config:
                raise ValueError(f"SUBAGENT dependency '{dep_name}' missing required field: 'git'")
            if 'git_tag' not in dep_config:
                raise ValueError(f"SUBAGENT dependency '{dep_name}' missing required field: 'git_tag'")
        
        elif dep_type == 'MCP':
            if 'command' not in dep_config:
                raise ValueError(f"MCP dependency '{dep_name}' missing required field: 'command'")
            if 'args' not in dep_config:
                raise ValueError(f"MCP dependency '{dep_name}' missing required field: 'args'")
        
        else:
            raise ValueError(f"Dependency '{dep_name}' has invalid type: {dep_type}. Must be 'SKILL', 'SUBAGENT', or 'MCP'")
    
    @property
    def version(self) -> str:
        """Get the configuration format version."""
        return self.config.get('version', DEFAULT_CONFIG_VERSION)

    @property
    def target_agents(self) -> List[str]:
        """Get the target agents."""
        return self.config['target_agents']
    
    @property
    def dependencies(self) -> Dict[str, Dict[str, Any]]:
        """Get the dependencies dictionary."""
        return self.config['dependencies']
    
    def get_skills(self) -> Dict[str, Dict[str, Any]]:
        """Get all SKILL dependencies."""
        return {
            name: config for name, config in self.dependencies.items()
            if config.get('type') == 'SKILL'
        }
    
    def get_subagents(self) -> Dict[str, Dict[str, Any]]:
        """Get all SUBAGENT dependencies."""
        return {
            name: config for name, config in self.dependencies.items()
            if config.get('type') == 'SUBAGENT'
        }
    
    def get_mcps(self) -> Dict[str, Dict[str, Any]]:
        """Get all MCP dependencies."""
        return {
            name: config for name, config in self.dependencies.items()
            if config.get('type') == 'MCP'
        }

    def get_agent_config(self, agent_name: str) -> Dict[str, Any]:
        """
        Get configuration for a specific agent.

        Args:
            agent_name: Name of the agent (e.g., 'claude', 'qoder', 'iflow')

        Returns:
            Agent configuration dictionary, or empty dict if not configured
        """
        agent_configs = self.config.get('agent_config', {})
        return agent_configs.get(agent_name, {})

    # Built-in agent CLI command mappings
    _BUILTIN_CLI_COMMANDS = {
        'qoder': 'qodercli',
    }

    # Built-in agent MCP command mappings
    _BUILTIN_MCP_COMMANDS = {
        'qoder': {'add': 'add', 'remove': 'remove', 'format': 'expanded'},
    }

    def get_agent_cli_command(self, agent_name: str) -> str:
        """
        Get the CLI command for an agent.

        Args:
            agent_name: Name of the agent

        Returns:
            CLI command to use (e.g., 'claude', 'qodercli')
        """
        # Check user config first
        agent_config = self.get_agent_config(agent_name)
        if 'cli_command' in agent_config:
            return agent_config['cli_command']

        # Fall back to built-in mapping
        if agent_name in self._BUILTIN_CLI_COMMANDS:
            return self._BUILTIN_CLI_COMMANDS[agent_name]

        # Default: use agent name as command
        return agent_name

    def get_agent_mcp_commands(self, agent_name: str) -> Dict[str, str]:
        """
        Get MCP subcommands for an agent.

        Args:
            agent_name: Name of the agent

        Returns:
            Dictionary with 'add' and 'remove' command names
        """
        # Check user config first
        agent_config = self.get_agent_config(agent_name)
        user_add = agent_config.get('mcp_add_command')
        user_remove = agent_config.get('mcp_remove_command')

        if user_add or user_remove:
            return {
                'add': user_add or 'add-json',
                'remove': user_remove or 'remove',
                'format': agent_config.get('mcp_format', 'json')
            }

        # Fall back to built-in mapping
        if agent_name in self._BUILTIN_MCP_COMMANDS:
            return self._BUILTIN_MCP_COMMANDS[agent_name].copy()

        # Default: add-json / remove
        return {'add': 'add-json', 'remove': 'remove', 'format': 'json'}


def find_vibe_package_config(start_dir: str = None) -> Path:
    """
    Find vibe_package.json in current directory or parent directories.
    
    Args:
        start_dir: Directory to start searching from (default: current directory)
    
    Returns:
        Path to vibe_package.json file
    
    Raises:
        FileNotFoundError: If vibe_package.json is not found
    """
    if start_dir is None:
        start_dir = os.getcwd()
    
    current_dir = Path(start_dir).resolve()
    
    while True:
        config_path = current_dir / 'vibe_package.json'
        if config_path.exists():
            return config_path
        
        parent = current_dir.parent
        if parent == current_dir:
            # Reached root directory
            raise FileNotFoundError("vibe_package.json not found in current directory or parent directories")
        
        current_dir = parent