"""Agent configuration service."""

from typing import List, Dict, Any, Optional
from sqlalchemy.orm import Session
from sqlalchemy import and_, select, update

from ..models.agent_config import AgentConfig
from utils.util_exceptions import ValidationError, NotFoundError
from loguru import logger


class AgentConfigService:
    """Service for managing agent configurations."""
    
    def __init__(self, db: Session):
        self.db = db
    
    async def create_config(self, config_data: Dict[str, Any]) -> AgentConfig:
        """Create a new agent configuration."""
        try:
            # Validate required fields
            if not config_data.get("name"):
                raise ValidationError("Configuration name is required")
            
            # Check if name already exists
            stmt = select(AgentConfig).where(AgentConfig.name == config_data["name"])
            existing = (await self.db.execute(stmt)).scalar_one_or_none()
            if existing:
                raise ValidationError(f"Configuration with name '{config_data['name']}' already exists")
            
            # Create new configuration
            config = AgentConfig(
                name=config_data["name"],
                description=config_data.get("description", ""),
                enabled_tools=config_data.get("enabled_tools", ["calculator", "weather", "search", "datetime", "file"]),
                max_iterations=config_data.get("max_iterations", 10),
                temperature=config_data.get("temperature", 0.1),
                system_message=config_data.get("system_message", "You are a helpful AI assistant with access to various tools. Use the available tools to help answer user questions accurately. Always explain your reasoning and the tools you're using."),
                verbose=config_data.get("verbose", True),
                is_active=config_data.get("is_active", True),
                is_default=config_data.get("is_default", False)
            )
            
            # If this is set as default, unset other defaults
            if config.is_default:
                stmt = update(AgentConfig).where(AgentConfig.is_default == True).values({"is_default": False})
                await self.db.execute(stmt)
            
            self.db.add(config)
            await self.db.commit()
            await self.db.refresh(config)
            
            logger.info(f"Created agent configuration: {config.name}")
            return config
            
        except Exception as e:
            await self.db.rollback()
            logger.error(f"Error creating agent configuration: {str(e)}")
            raise
    
    async def get_config(self, config_id: int) -> Optional[AgentConfig]:
        """Get agent configuration by ID."""
        stmt = select(AgentConfig).where(AgentConfig.id == config_id)
        return (await self.db.execute(stmt)).scalar_one_or_none()
    
    async def get_config_by_name(self, name: str) -> Optional[AgentConfig]:
        """Get agent configuration by name."""
        stmt = select(AgentConfig).where(AgentConfig.name == name)
        return (await self.db.execute(stmt)).scalar_one_or_none()
    
    async def get_default_config(self) -> Optional[AgentConfig]:
        """Get default agent configuration."""
        stmt = select(AgentConfig).where(and_(AgentConfig.is_default == True, AgentConfig.is_active == True))
        return (await self.db.execute(stmt)).scalar_one_or_none()
    
    def list_configs(self, active_only: bool = True) -> List[AgentConfig]:
        """List all agent configurations."""
        stmt = select(AgentConfig)
        if active_only:
            stmt = stmt.where(AgentConfig.is_active == True)
        stmt = stmt.order_by(AgentConfig.created_at.desc())
        return self.db.execute(stmt).scalars().all()
    
    async def update_config(self, config_id: int, config_data: Dict[str, Any]) -> AgentConfig:
        """Update agent configuration."""
        try:
            config = await self.get_config(config_id)
            if not config:
                raise NotFoundError(f"Agent configuration with ID {config_id} not found")
            
            # Check if name change conflicts with existing
            if "name" in config_data and config_data["name"] != config.name:
                stmt = select(AgentConfig).where(
                    and_(
                        AgentConfig.name == config_data["name"],
                        AgentConfig.id != config_id
                    )
                )
                existing = (await self.db.execute(stmt)).scalar_one_or_none()
                if existing:
                    raise ValidationError(f"Configuration with name '{config_data['name']}' already exists")
            
            # Update fields
            for key, value in config_data.items():
                if hasattr(config, key):
                    setattr(config, key, value)
            
            # If this is set as default, unset other defaults
            if config_data.get("is_default", False):
                stmt = update(AgentConfig).where(
                    and_(
                        AgentConfig.is_default == True,
                        AgentConfig.id != config_id
                    )
                ).values({"is_default": False})
                await self.db.execute(stmt)
            
            await self.db.commit()
            await self.db.refresh(config)
            
            logger.info(f"Updated agent configuration: {config.name}")
            return config
            
        except Exception as e:
            await self.db.rollback()
            logger.error(f"Error updating agent configuration: {str(e)}")
            raise
    
    async def delete_config(self, config_id: int) -> bool:
        """Delete agent configuration (soft delete by setting is_active=False)."""
        try:
            config = await self.get_config(config_id)
            if not config:
                raise NotFoundError(f"Agent configuration with ID {config_id} not found")
            
            # Don't allow deleting the default configuration
            if config.is_default:
                raise ValidationError("Cannot delete the default configuration")
            
            config.is_active = False
            self.db.commit()
            
            logger.info(f"Deleted agent configuration: {config.name}")
            return True
            
        except Exception as e:
            await self.db.rollback()
            logger.error(f"Error deleting agent configuration: {str(e)}")
            raise
    
    async def set_default_config(self, config_id: int) -> AgentConfig:
        """Set a configuration as default."""
        try:
            config = await self.get_config(config_id)
            if not config:
                raise NotFoundError(f"Agent configuration with ID {config_id} not found")
            
            if not config.is_active:
                raise ValidationError("Cannot set inactive configuration as default")
            
            # Unset other defaults
            stmt = update(AgentConfig).where(AgentConfig.is_default == True).values({"is_default": False})
            await self.db.execute(stmt)
            
            # Set this as default
            config.is_default = True
            await self.db.commit()
            await self.db.refresh(config)
            
            logger.info(f"Set default agent configuration: {config.name}")
            return config
            
        except Exception as e:
            await self.db.rollback()
            logger.error(f"Error setting default agent configuration: {str(e)}")
            raise
    
    async def get_config_dict(self, config_id: Optional[int] = None) -> Dict[str, Any]:
        """Get configuration as dictionary. If no ID provided, returns default config."""
        if config_id:
            config = await self.get_config(config_id)
        else:
            config = await self.get_default_config()
        
        if not config:
            # Return default values if no configuration found
            return {
                "enabled_tools": ["calculator", "weather", "search", "datetime", "file", "generate_image"],
                "max_iterations": 10,
                "temperature": 0.1,
                "system_message": "You are a helpful AI assistant with access to various tools. Use the available tools to help answer user questions accurately. Always explain your reasoning and the tools you're using.",
                "verbose": True
            }
        
        return {
            "enabled_tools": config.enabled_tools,
            "max_iterations": config.max_iterations,
            "temperature": config.temperature,
            "system_message": config.system_message,
            "verbose": config.verbose
        }