"""
Agent Config Loader
====================
Searches the user's current working directory for an `evalmonkey.yaml` file.
This is the same pattern used by promptfoo, pytest, docker-compose, eslint, etc.

Users cd into their own project repo and run `evalmonkey` — it auto-discovers the config.
"""
import os
import yaml
from typing import Optional
from dataclasses import dataclass, field


CONFIG_FILENAME = "evalmonkey.yaml"

# Pre-built presets per framework — correct request/response shape out of the box
FRAMEWORK_PRESETS = {
    "crewai": {
        "description": "CrewAI multi-agent framework",
        "default_port": 8000,
        "default_path": "/chat",
        "request_key": "message",
        "response_path": "reply",
    },
    "langchain": {
        "description": "LangChain / LangServe",
        "default_port": 8000,
        "default_path": "/chain/invoke",
        "request_key": "input",
        "response_path": "output",
    },
    "openai": {
        "description": "OpenAI Agents SDK / Chat Completions",
        "default_port": 8000,
        "default_path": "/v1/chat/completions",
        "request_key": "content",
        "response_path": "choices.0.message.content",
    },
    "bedrock": {
        "description": "AWS Bedrock Agent Core / Converse API",
        "default_port": 8000,
        "default_path": "/solve",
        "request_key": "prompt",
        "response_path": "output.text",
    },
    "autogen": {
        "description": "Microsoft AutoGen",
        "default_port": 8000,
        "default_path": "/chat",
        "request_key": "message",
        "response_path": "data",
    },
    "ollama": {
        "description": "Ollama local LLM server",
        "default_port": 11434,
        "default_path": "/api/chat",
        "request_key": "messages",
        "response_path": "message.content",
    },
    "strands": {
        "description": "AWS Strands SDK agent",
        "default_port": 8001,
        "default_path": "/solve",
        "request_key": "question",
        "response_path": "data",
    },
    "custom": {
        "description": "Any custom HTTP agent",
        "default_port": 8000,
        "default_path": "/solve",
        "request_key": "question",
        "response_path": "data",
    },
}

# Maps each agent_type to the most relevant standard benchmark IDs.
# Used by `evalmonkey recommend` to surface a curated suite instead of all 22.
AGENT_TYPE_BENCHMARKS: dict[str, list[str]] = {
    "research_agent":    ["hotpotqa", "drop", "natural-questions", "gaia-benchmark"],
    "coding_agent":      ["human-eval", "mbpp", "apps", "swe-bench"],
    "rag_agent":         ["hotpotqa", "natural-questions", "drop", "truthfulqa"],
    "customer_support":  ["daily-dialog", "multiwoz", "mt-bench", "alpacaeval"],
    "voice_agent":       ["daily-dialog", "multiwoz", "spokentext-cleanup"],
    "safety_agent":      ["truthfulqa", "toxigen", "arc", "bbh"],
    "general":           ["gsm8k", "mmlu", "arc", "truthfulqa"],
}


@dataclass
class AgentConfig:
    """Parsed agent configuration."""
    name: str = "My Agent"
    url: str = "http://localhost:8000/solve"
    framework: str = "custom"
    request_key: str = "question"
    response_path: str = "data"
    eval_model: str = ""
    agent_command: str = ""         # shell command to start the agent server
    agent_startup_wait: int = 3     # seconds to wait after spawning before sending traffic
    agent_type: str = "general"     # Used by `evalmonkey recommend` to surface relevant benchmarks
    private_benchmarks: list = field(default_factory=list)  # Custom REST dataset configs
    extra: dict = field(default_factory=dict)


def load_config(config_path: Optional[str] = None) -> Optional[AgentConfig]:
    """
    Load evalmonkey.yaml from:
      1. An explicit --config path (if provided)
      2. The current working directory (CWD)

    Returns None if no config file is found (CLI flags take over).
    """
    candidates = []
    if config_path:
        candidates.append(config_path)
    candidates.append(os.path.join(os.getcwd(), CONFIG_FILENAME))

    for path in candidates:
        if os.path.exists(path):
            with open(path) as f:
                raw = yaml.safe_load(f) or {}
            agent_raw = raw.get("agent", {})
            return AgentConfig(
                name=str(agent_raw.get("name", "My Agent")),
                url=str(agent_raw.get("url", "http://localhost:8000/solve")),
                framework=str(agent_raw.get("framework", "custom")),
                request_key=str(agent_raw.get("request_key", "question")),
                response_path=str(agent_raw.get("response_path", "data")),
                eval_model=str(raw.get("eval_model", os.getenv("EVAL_MODEL", ""))),
                agent_command=str(agent_raw.get("agent_command", "")),
                agent_startup_wait=int(agent_raw.get("agent_startup_wait", 3)),
                agent_type=str(agent_raw.get("agent_type", "general")),
                private_benchmarks=list(raw.get("private_benchmarks", [])),
                extra=raw,
            )
    return None


def generate_config_yaml(framework: str, name: str, port: int) -> str:
    """Generate a pre-filled evalmonkey.yaml for a given framework."""
    preset = FRAMEWORK_PRESETS.get(framework, FRAMEWORK_PRESETS["custom"])
    url = f"http://localhost:{port}{preset['default_path']}"
    return f"""# evalmonkey.yaml — generated by EvalMonkey
# Run from the same directory as this file:
#   evalmonkey run-benchmark --scenario mmlu
#
# Framework: {preset['description']}
# Docs: https://github.com/Corbell-AI/evalmonkey

agent:
  name: "{name}"
  framework: {framework}
  url: {url}

  # (Optional) Shell command to start your agent server automatically.
  # EvalMonkey will spawn it, wait for it to be ready, benchmark, then stop it.
  # Comment this out if you start your server manually.
  #
  # Examples:
  #   agent_command: python3.11 src/agent.py
  #   agent_command: uvicorn src.agent:app --port {port}
  #   agent_command: node server.js
  agent_command: ""   # ← fill in your start command, or leave blank to manage manually
  agent_startup_wait: 3   # seconds to wait after launch before sending traffic

  # How EvalMonkey sends questions to your agent
  request_key: {preset['request_key']}   # payload key for the question

  # How EvalMonkey reads the answer back (dot-notation for nested fields)
  response_path: {preset['response_path']}   # dot-path to extract the answer text

  # Agent type — drives `evalmonkey recommend` to show only relevant benchmarks
  # Options: general | research_agent | coding_agent | rag_agent | customer_support | voice_agent | safety_agent
  agent_type: general

# Which LLM EvalMonkey uses as the judge (can also be set via EVAL_MODEL env var)
eval_model: "gpt-4o"   # or: anthropic.claude-3-haiku-20240307-v1:0, ollama/llama3, etc.
"""
