"""
AgentConfig Schema (Pydantic V2)
================================
Replaces the dataclass ModelDefinition.
Keeps the same fields and from_yaml() interface.
"""

from __future__ import annotations

from pathlib import Path
from typing import Any, Optional

from pydantic import BaseModel, Field, field_validator


class AgentConfig(BaseModel):
    """
    Configuration for a single Agent.
    Maps 1:1 with the agent YAML config file.

    Paths are RELATIVE to the agent's directory (e.g. "instruction.md").
    The Agent class resolves them against base_agents_dir/agents/{name}/.
    """

    # --- Agent Identity ---
    name: str = Field(..., description="Agent name, e.g. 'hopahopa', 'analyzer'")
    agent_id: str = Field("", description="Unique node ID, e.g. 'node_1770596488344_qv7tjhi'")
    description: str = Field("", description="Human-readable description")
    provide: str = Field("", description="What this agent provides (optional metadata)")

    # --- Model Configuration ---
    model: str = Field("gpt-4", description="Engine name, e.g. 'gpt-4', 'claude-sonnet-4', 'gemini-pro', 'llama3.1'")
    provider: Optional[str] = Field(None, description="Force provider: 'openai', 'anthropic', 'google', 'ollama'. Auto-detected if None.")
    temperature: float = Field(0.0, ge=0.0, le=2.0)
    max_tokens: Optional[int] = Field(None, gt=0)

    # --- Prompt Files (relative to agent dir) ---
    instruction_path: Optional[Path] = None
    think_path: Optional[Path] = None
    return_path: Optional[Path] = None
    next_model_rule_path: Optional[Path] = None
    example_path: Optional[Path] = None

    # --- Processing Functions ---
    preprocess_path: Optional[Path] = None
    preprocess_function_name: Optional[str] = Field("preprocess")

    postprocess_path: Optional[Path] = None
    postprocess_function_name: Optional[str] = Field("postprocess")

    # --- Output Format Configuration ---
    return_format: Optional[str] = Field("text", description="'json' / 'json_object' / 'text' / 'markdown'")
    json_schema_path: Optional[Path] = None
    return_format_function_path: Optional[Path] = None
    return_format_function_name: Optional[str] = None

    class Config:
        extra = "ignore"  # Old YAML files with unknown keys won't break

    @field_validator(
        "instruction_path", "think_path", "return_path",
        "next_model_rule_path", "example_path", "json_schema_path",
        "preprocess_path", "postprocess_path",
        "return_format_function_path",
        mode="before",
    )
    @classmethod
    def _coerce_path(cls, v: Any) -> Optional[Path]:
        if v is None or v == "" or v == "null":
            return None
        return Path(v)

    @classmethod
    def from_yaml(cls, agent_name: str, config: dict) -> "AgentConfig":
        """
        Create an AgentConfig from a YAML config dictionary.

        Args:
            agent_name: The name of the agent (YAML key)
            config: The agent configuration dict (YAML value)

        Returns:
            AgentConfig instance

        Example:
            >>> yaml_data = yaml.safe_load(open('hopahopa.yaml'))
            >>> config_dict = yaml_data['hopahopa']
            >>> agent_cfg = AgentConfig.from_yaml('hopahopa', config_dict)
        """
        return cls(
            name=agent_name,
            agent_id=config.get("agent_id", ""),
            description=config.get("description", ""),
            provide=config.get("provide", ""),

            model=config.get("model", "gpt-4"),
            provider=config.get("provider"),
            temperature=config.get("temperature", 0.0),
            max_tokens=config.get("max_tokens"),

            # Support legacy key 'instruction' as fallback
            instruction_path=config.get("instruction_path") or config.get("instruction"),
            think_path=config.get("think_path"),
            return_path=config.get("return_path"),
            next_model_rule_path=config.get("next_model_rule_path"),
            example_path=config.get("example_path"),

            preprocess_path=config.get("preprocess_path"),
            preprocess_function_name=config.get("preprocess_function_name", "preprocess"),

            postprocess_path=config.get("postprocess_path"),
            postprocess_function_name=config.get("postprocess_function_name", "postprocess"),

            return_format=config.get("return_format", "text"),
            json_schema_path=config.get("json_schema_path"),
            return_format_function_path=config.get("return_format_function_path"),
            return_format_function_name=config.get("return_format_function_name"),
        )