"""
Lab 6.8: Build an Eval Harness -- SOLUTION

Golden Q&A pairs + automated pass/fail scoring with pass@k.
"""

from typing import Callable

GOLDEN_DATASET = [
    {"id": "t001", "input": "Find users created in last 24h",
     "expected_tools": ["query_database"],
     "expected_params": {"query": "SELECT * FROM users WHERE created_at > now() - interval '24 hours'"},
     "expected_output_contains": ["users"], "weight": 1.0},
    {"id": "t002", "input": "Search for AI agent frameworks",
     "expected_tools": ["search_web"],
     "expected_output_contains": ["framework"], "weight": 1.0},
    {"id": "t003", "input": "Deploy build to staging",
     "expected_tools": ["run_deploy"],
     "expected_params": {"environment": "staging"},
     "expected_output_contains": ["deploy"], "weight": 1.5},
    {"id": "t004", "input": "Explain recursion",
     "expected_tools": [],
     "expected_output_contains": ["base case"], "weight": 0.5},
    {"id": "t005", "input": "Fix vulnerability in auth.py",
     "expected_tools": ["read_file", "edit_file"],
     "expected_output_contains": ["fixed"], "weight": 2.0},
    {"id": "t006", "input": "What's the stock price of AAPL?",
     "expected_tools": ["fetch_stock_price", "search_web"],
     "expected_output_contains": ["AAPL", "$"], "weight": 1.0},
    {"id": "t007", "input": "Send a welcome email to new@user.com",
     "expected_tools": ["send_email"],
     "expected_params": {"to": "new@user.com"},
     "expected_output_contains": ["sent"], "weight": 1.5},
    {"id": "t008", "input": "Analyze this CSV: sales.csv",
     "expected_tools": ["read_file", "analyze_data"],
     "expected_output_contains": ["revenue", "average"], "weight": 1.5},
    {"id": "t009", "input": "What packages are in package.json?",
     "expected_tools": ["read_file"],
     "expected_output_contains": ["dependencies"], "weight": 0.5},
    {"id": "t010", "input": "Create a SQL migration for users table",
     "expected_tools": ["write_file"],
     "expected_params": {"path": "migrations/"},
     "expected_output_contains": ["CREATE TABLE"], "weight": 1.5},
]


class EvalHarness:
    def __init__(self, dataset: list[dict]):
        self.dataset = dataset
    
    def score_case(self, result: Any, test_case: dict) -> float:
        score = 0.0
        max_score = 0.0
        
        expected_tools = set(test_case.get("expected_tools", []))
        actual_tools = set(t.get("tool") for t in result.get("tool_calls", []))
        if expected_tools:
            overlap = expected_tools & actual_tools
            score += len(overlap) / len(expected_tools) * 0.4
            max_score += 0.4
        else:
            score += 0.4
            max_score += 0.4
        
        expected_params = test_case.get("expected_params", {})
        if expected_params:
            for at in result.get("tool_calls", []):
                for key, val in expected_params.items():
                    if at.get("params", {}).get(key) == val:
                        score += 0.3 / len(expected_params)
            max_score += 0.3
        else:
            score += 0.3
            max_score += 0.3
        
        output = result.get("output", "")
        expected_out = test_case.get("expected_output_contains", [])
        if expected_out:
            matches = sum(1 for s in expected_out if s.lower() in output.lower())
            score += (matches / len(expected_out)) * 0.3
            max_score += 0.3
        else:
            score += 0.3
            max_score += 0.3
        
        return score / max_score if max_score > 0 else 0.0
    
    def evaluate(self, agent_func: Callable, k_values: list[int] = None) -> dict:
        if k_values is None:
            k_values = [1, 3, 5]
        
        k_results = {k: [] for k in k_values}
        
        for case in self.dataset:
            all_attempts = []
            max_k = max(k_values)
            for _ in range(max_k):
                result = agent_func(case["input"])
                score = self.score_case(result, case)
                all_attempts.append(score)
            
            for k in k_values:
                attempts = all_attempts[:k]
                best = max(attempts)
                passed = best >= 0.7
                k_results[k].append({
                    "case_id": case["id"],
                    "best_score": round(best, 3),
                    "passed": passed,
                    "all_scores": [round(s, 3) for s in attempts],
                    "weight": case.get("weight", 1.0)
                })
        
        output = {}
        for k in k_values:
            results = k_results[k]
            weighted_pass = sum(r["weight"] for r in results if r["passed"])
            total_weight = sum(r["weight"] for r in results)
            pass_rate = weighted_pass / total_weight if total_weight > 0 else 0
            
            all_passed = sum(1 for r in results if r["passed"])
            consistency = sum(1 for r in results if all(s >= 0.7 for s in r["all_scores"])) / len(results) if results else 0
            
            output[f"pass@{k}"] = round(pass_rate, 3)
            output[f"pass^{k}"] = round(consistency, 3)
            output[f"results_{k}"] = results
        
        output["total_cases"] = len(self.dataset)
        output["weighted_scores"] = {f"pass@{k}": output[f"pass@{k}"] for k in k_values}
        
        return output


def example_agent(input_text: str) -> dict:
    """Example agent that simulates responses for testing."""
    from difflib import SequenceMatcher
    
    for case in GOLDEN_DATASET:
        ratio = SequenceMatcher(None, input_text.lower(), case["input"].lower()).ratio()
        if ratio > 0.3:
            return {
                "tool_calls": [{"tool": t, "params": case.get("expected_params", {}) or {}} for t in case["expected_tools"]],
                "output": f"Result for: {case['input']}. Found relevant data."
            }
    
    return {"tool_calls": [], "output": "I can help with that."}


if __name__ == "__main__":
    harness = EvalHarness(GOLDEN_DATASET)
    results = harness.evaluate(example_agent, k_values=[1, 3, 5])
    
    print("=" * 55)
    print(" EVAL HARNESS RESULTS")
    print("=" * 55)
    
    for k in [1, 3, 5]:
        print(f"\npass@{k}:  {results[f'pass@{k}']:.1%}")
        print(f"pass^{k}:  {results[f'pass^{k}']:.1%}")
    
    print(f"\nTotal test cases: {results['total_cases']}")
    print("\nDetailed results (pass@3):")
    for r in results["results_3"]:
        icon = "+" if r["passed"] else "-"
        print(f"  {icon} {r['case_id']}: best={r['best_score']:.1%} attempts={r['all_scores']}")
