from pathlib import Path
from typing import List, Optional, Tuple, Union

import yaml
from pydantic import BaseModel, Field, HttpUrl


class HumanBaseline(BaseModel):
    """Human baseline result for a specific model on a task"""

    metric: str  # e.g., "pass@1"
    score: float  # e.g., 90.2
    source: HttpUrl  # URL to source of the baseline result


class TaskMetadata(BaseModel):
    """A specific task within an evaluation"""

    name: str  # e.g., "humaneval"
    dataset_samples: int
    human_baseline: Optional[HumanBaseline] = None


class EvalMetadata(BaseModel):
    """An evaluation benchmark"""

    title: str
    description: str
    path: str  # e.g., "src/inspect_evals/humaneval"
    arxiv: Optional[HttpUrl] = None
    group: str  # e.g., "Coding"
    contributors: List[str]
    tasks: List[TaskMetadata]
    tags: Optional[List[str]] = None

    @property
    def id(self) -> str:
        """Get the evaluation ID from the path"""
        return self.path.split("/")[-1]


class EvalListing(BaseModel):
    """Complete listing of all evaluations"""

    evals: List[EvalMetadata] = Field(alias="_root")

    @property
    def groups(self) -> List[str]:
        """Get all unique groups"""
        return sorted(list(set(eval.group for eval in self.evals)))

    def get_eval(self, eval_id: str) -> Optional[EvalMetadata]:
        """Get an evaluation by its ID"""
        for eval in self.evals:
            if eval.id == eval_id:
                return eval
        return None

    def get_evals_in_group(self, group: str) -> List[EvalMetadata]:
        """Get all evaluations in a specific group"""
        return [eval for eval in self.evals if eval.group == group]

    def find_task(
        self, task_name: str
    ) -> Tuple[Optional[EvalMetadata], Optional[TaskMetadata]]:
        """Find the evaluation and task by the task name"""
        for eval in self.evals:
            for task in eval.tasks:
                if task.name == task_name:
                    return eval, task
        return None, None


def _load_eval_listing(yaml_path: Union[str, Path]) -> EvalListing:
    """Load the evaluation listing from a YAML file"""
    with open(yaml_path) as f:
        data = yaml.safe_load(f)
        return EvalListing(_root=data)


def load_listing() -> EvalListing:
    """Load the evaluation listing from the package directory."""
    # Look in the same directory as the metadata.py file
    listing_path = Path(__file__).parent / "listing.yaml"
    return _load_eval_listing(listing_path)


# Example usage:
"""
# Get all groups
print(f"Available groups: {listing.groups}")

# Get all coding evals
coding_evals = listing.get_evals_in_group('Coding')
for eval in coding_evals:
    print(f"Found coding eval: {eval.title}")

# Get a specific task
cybermetric, cybermetric_500 = listing.find_task('cybermetric_500')
if cybermetric:
    print(f"CyberMetric has {len(cybermetric.tasks)} tasks")
"""
