"""
Base Classes for Pixel Agents
This module provides the base classes and utilities for creating agents in the Pixel system.
"""

import logging
from typing import Optional, Dict, Any, List
from pathlib import Path

from agentscope.agent import ReActAgent
from agentscope.formatter import OpenAIChatFormatter
from agentscope.message import Msg
from agentscope.tool import Toolkit
from agentscope.plan import PlanNotebook

from src.services.provider.agentscope_adapter import PixelAgentScopeModel
from src.services.agent_engine.toolkit import ToolkitFactory

logger = logging.getLogger(__name__)

def create_default_model(
    model_name: str,
    provider: str = "dashscope",
    base_url: Optional[str] = None,
    api_key: Optional[str] = None
) -> PixelAgentScopeModel:
    """
    Create a configured PixelAgentScopeModel instance.
    
    Args:
        model_name: Name of the model (e.g. "qwen-plus")
        provider: Provider name (default: "dashscope")
        base_url: Optional custom base URL
        api_key: Optional API key
        
    Returns:
        Configured PixelAgentScopeModel
    """
    overrides = {}
    if base_url:
        overrides["base_url"] = base_url
    if api_key:
        overrides["api_key"] = api_key
        
    return PixelAgentScopeModel(
        provider=provider,
        model_name=model_name,
        **overrides
    )

class BasePixelAgent:
    """Base class for all Pixel agents."""
    pass

class SkillBasedAgent(ReActAgent):
    """
    An agent that uses a specific Skill to guide its behavior.
    Inherits from ReActAgent to support tool usage and reasoning.
    """
    
    def __init__(
        self,
        name: str,
        skill_name: str,
        model: Any,
        skill_domain: str = "film_production",
        verbose: bool = True,
        base_sys_prompt: Optional[str] = None,
        load_reference: bool = True,
        **kwargs
    ):
        """
        Initialize a SkillBasedAgent.
        
        Args:
            name: Agent name
            skill_name: Name of the skill folder (e.g. "screenwriting")
            model: Model config/instance
            skill_domain: Domain folder for the skill (default: "film_production")
            verbose: Whether to log verbose output
            base_sys_prompt: Optional base system prompt to prepend
            load_reference: Whether to load reference.md if available
            **kwargs: Additional args for ReActAgent
        """
        self.skill_name = skill_name
        self.skill_domain = skill_domain
        self.load_reference = load_reference
        
        # 1. Load System Prompt from Skill
        skill_prompt = self._load_skill_prompt()
        
        # Combine base prompt and skill prompt
        sys_prompt = skill_prompt
        if base_sys_prompt:
            sys_prompt = f"{base_sys_prompt}\n\n{skill_prompt}"
            
        # 2. Get Toolkit (Shared)
        # We load the toolkit for the specific domain or all relevant domains
        toolkit = ToolkitFactory.get_toolkit(skill_domains=[skill_domain, "general"])
        
        # 3. Initialize ReActAgent
        # Note: verbose is handled via kwargs or not supported in this version's ReActAgent
        # We pass other kwargs to super
        super().__init__(
            name=name,
            sys_prompt=sys_prompt,
            model=model,
            formatter=OpenAIChatFormatter(),
            toolkit=toolkit,
            plan_notebook=PlanNotebook(),
            **kwargs
        )
        
    def _load_skill_prompt(self) -> str:
        """
        Load the skill prompt from the SKILL.md file.
        Also loads reference.md and templates if needed.
        """
        try:
            # Construct path to skill directory
            # Assuming structure: agent_core/skills/{domain}/{skill_name}/SKILL.md
            base_dir = Path(__file__).parent / "skills"
            skill_dir = base_dir / self.skill_domain / self.skill_name
            skill_file = skill_dir / "SKILL.md"
            
            skill_content = ""
            if skill_file.exists():
                with open(skill_file, "r", encoding="utf-8") as f:
                    skill_content = f.read()
            else:
                logger.warning(f"Skill file not found: {skill_file}.")
                
            # Progressive Disclosure:
            # Instead of loading the full content of reference.md, we provide a manifest of available resources.
            # This encourages the agent to use tools (read_file) to access knowledge on demand.
            if self.load_reference:
                resources = []
                # Check for reference.md
                ref_file = skill_dir / "reference.md"
                if ref_file.exists():
                    resources.append(f"- reference.md: Comprehensive guide and domain knowledge for {self.skill_name}")
                
                # Check for templates directory
                templates_dir = skill_dir / "templates"
                if templates_dir.exists() and templates_dir.is_dir():
                    for tmpl in templates_dir.glob("*"):
                        if tmpl.is_file():
                             resources.append(f"- templates/{tmpl.name}: Template file")
                             
                if resources:
                    resource_prompt = "\n\n## 📂 Available Knowledge Resources\nThe following resources are available for you to reference. Use the `read_file` tool to read them when needed:\n"
                    resource_prompt += "\n".join(resources)
                    resource_prompt += f"\n\nBase path for these files: {skill_dir}"
                    
                    skill_content += resource_prompt
            
            return skill_content if skill_content else f"You are {self.name}."
            
        except Exception as e:
            logger.error(f"Failed to load skill prompt for {self.skill_name}: {e}")
            return f"You are {self.name}. (Error loading skill)"
