"""
Agent tool-call evaluation — run locally, upload results to evalkit server.

This example demonstrates local evaluation with server-side result storage:
  1. Run an agent on test scenarios and capture its tool calls
  2. Evaluate tool usage locally with AgentToolCallSuite
  3. Upload the results to the server for the web dashboard

Unlike server_rag.py (where the server runs the judge), here the evaluation
runs locally and only the results are uploaded. This is useful when you want
full control over the judge configuration or when the server doesn't have
access to the LLM API.

Requirements:
    pip install evalkit-llm[openai]
    export OPENAI_API_KEY=sk-...
    # Start the server in another terminal: evalkit serve

Usage:
    python examples/server_agent.py
    python examples/server_agent.py http://my-server:9000   # custom server URL
"""

from __future__ import annotations

import argparse
import json
import os

from dotenv import load_dotenv

load_dotenv()

from openai import OpenAI

from evalkit import AgentToolCallSuite, EvalKitClient, EvaluationEngine, TestCase, ToolCall
from evalkit.judges.openai import OpenAIJudge

# OpenAI function-calling tool definitions
TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the current weather for a given city.",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "The city name"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                },
                "required": ["city"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "search_web",
            "description": "Search the web for information on a topic.",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "The search query"},
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "Evaluate a mathematical expression.",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {"type": "string", "description": "e.g. '2 + 2'"},
                },
                "required": ["expression"],
            },
        },
    },
]

# Test scenarios: question + expected tool calls
SCENARIOS = [
    (
        "What is the weather like in Paris right now?",
        [{"name": "get_weather", "parameters": {"city": "Paris"}}],
    ),
    (
        "Search the web for the latest news about Python 4.",
        [{"name": "search_web", "parameters": {"query": "Python 4 latest news"}}],
    ),
    (
        "Calculate 15 multiplied by 37.",
        [{"name": "calculate", "parameters": {"expression": "15 * 37"}}],
    ),
]


def run_agent(question: str) -> list[dict]:
    """Call the OpenAI API with tools and return the tool calls made."""
    client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "You are a helpful assistant. Use the appropriate tool."},
            {"role": "user", "content": question},
        ],
        tools=TOOLS,
        tool_choice="auto",
    )
    message = response.choices[0].message
    if not message.tool_calls:
        return []
    return [{"name": tc.function.name, "parameters": json.loads(tc.function.arguments)} for tc in message.tool_calls]


def main() -> None:
    parser = argparse.ArgumentParser(description="Agent evaluation with server upload")
    parser.add_argument(
        "server_url",
        nargs="?",
        default="http://localhost:8000",
        help="evalkit server URL (default: http://localhost:8000)",
    )
    args = parser.parse_args()

    # Run agent on each scenario and capture tool calls
    print("Running agent and capturing tool calls…")
    test_cases = []
    for question, expected_raw in SCENARIOS:
        actual_raw = run_agent(question)
        expected = [ToolCall(**t) for t in expected_raw]
        actual = [ToolCall(**t) for t in actual_raw]
        test_cases.append(
            TestCase(
                question=question,
                expected_tool_calls=expected,
                actual_tool_calls=actual,
            )
        )
        print(f"  Q: {question}")
        print(f"    Expected: {[t.name for t in expected]}")
        print(f"    Actual:   {[t.name for t in actual]}")

    # Evaluate locally
    print("\nRunning evaluation…")
    engine = EvaluationEngine(judge=OpenAIJudge(model="gpt-4o-mini"))
    report = engine.run(test_cases=test_cases, suite=AgentToolCallSuite())
    report.print_report()

    # Upload results to server
    print(f"\nUploading results to {args.server_url}…")
    client = EvalKitClient(args.server_url)
    evaluation = client.upload_report("Agent Evaluation Demo", report)
    print(f"  Evaluation: {evaluation.id}")
    print(f"  Dashboard:  {args.server_url}/evaluations/{evaluation.id}")


if __name__ == "__main__":
    main()
