"""Benchmark Generator — Auto-generate benchmark cases from skill configs.

Reads configs/skills/*.yaml, extracts intent.keywords/description/examples,
and generates BenchmarkCase objects aligned with actual skill configurations.

This ensures the benchmark dataset stays in sync with the real skill registry.
"""

from pathlib import Path

import yaml
from pydantic import BaseModel, ConfigDict

from tests.e2e.benchmark_dataset import BenchmarkCase


# ═══════════════════════════════════════════════════════════════════════════
# Skill Config Model
# ═══════════════════════════════════════════════════════════════════════════


class SkillIntent(BaseModel):
    """Intent section of a skill config."""

    model_config = ConfigDict(extra="ignore")

    keywords: list[str] = []
    description: str = ""
    examples: list[str] = []


class SkillConfig(BaseModel):
    """Minimal skill config model for benchmark generation."""

    model_config = ConfigDict(extra="ignore")

    name: str
    description: str = ""
    execution_mode: str = "direct"
    task_mode: str = "llm_generate"
    intent: SkillIntent = SkillIntent()


# ═══════════════════════════════════════════════════════════════════════════
# Complexity Mapping
# ═══════════════════════════════════════════════════════════════════════════

EXECUTION_MODE_TO_COMPLEXITY: dict[str, str] = {
    "direct": "low",
    "react": "high",
    "rewoo": "high",
    "reflexion": "high",
    "plan_exec": "high",
    "tool_call": "medium",
    "llm_generate": "low",
    "custom": "medium",
}

# Paraphrase templates for auto-generating paraphrases from examples
PARAPHRASE_TEMPLATES_CN: list[str] = [
    "请帮我{action}",
    "我需要{action}",
    "能不能{action}",
]

PARAPHRASE_TEMPLATES_EN: list[str] = [
    "Please help me {action}",
    "I need to {action}",
    "Can you {action}",
]


# ═══════════════════════════════════════════════════════════════════════════
# Benchmark Generator
# ═══════════════════════════════════════════════════════════════════════════


class BenchmarkGenerator:
    """Generate benchmark cases from skill config YAML files."""

    def __init__(self, configs_dir: str | None = None) -> None:
        if configs_dir is None:
            # Default: project_root/configs/skills/
            project_root = Path(__file__).parent.parent.parent.parent
            configs_dir = str(project_root / "configs" / "skills")
        self.configs_dir = configs_dir
        self._skills: list[SkillConfig] = []
        self._loaded = False

    def load_skills(self) -> list[SkillConfig]:
        """Load all skill configs from YAML files."""
        if self._loaded:
            return self._skills

        skills_dir = Path(self.configs_dir)
        if not skills_dir.exists():
            return self._skills

        for yaml_file in sorted(skills_dir.glob("*.yaml")):
            with open(yaml_file, encoding="utf-8") as f:
                data = yaml.safe_load(f)
            if data and isinstance(data, dict):
                try:
                    skill = SkillConfig(**data)
                    self._skills.append(skill)
                except Exception:
                    continue

        self._loaded = True
        return self._skills

    def _get_effective_execution_mode(self, skill: SkillConfig) -> str:
        """Get the effective execution mode for a skill."""
        if skill.execution_mode and skill.execution_mode != "direct":
            return skill.execution_mode
        # Map task_mode to execution mode
        return skill.task_mode if skill.task_mode else "direct"

    def _generate_paraphrases(self, example: str, keywords: list[str]) -> list[str]:
        """Generate paraphrases for an example query."""
        paraphrases: list[str] = []

        # Simple paraphrase generation: add prefix variations
        is_chinese = any("\u4e00" <= c <= "\u9fff" for c in example)

        if is_chinese:
            # Chinese paraphrases
            if not example.startswith("请") and not example.startswith("帮"):
                paraphrases.append(f"请{example}")
            if not example.startswith("我"):
                paraphrases.append(f"我需要{example}")
            # Add keyword-based variant
            if keywords:
                kw = keywords[0]
                if kw not in example:
                    paraphrases.append(f"关于{kw}，{example}")
        else:
            # English paraphrases
            lower = example.lower()
            if not lower.startswith("please") and not lower.startswith("can you"):
                paraphrases.append(f"Please {example[0].lower()}{example[1:]}")
            if not lower.startswith("i need"):
                paraphrases.append(f"I need to {example[0].lower()}{example[1:]}")

        return paraphrases[:3]  # Max 3 paraphrases per example

    def generate_routing_benchmarks(self) -> list[BenchmarkCase]:
        """Generate routing benchmark cases from all skills."""
        skills = self.load_skills()
        cases: list[BenchmarkCase] = []
        case_counter = 0

        for skill in skills:
            exec_mode = self._get_effective_execution_mode(skill)
            complexity = EXECUTION_MODE_TO_COMPLEXITY.get(exec_mode, "low")

            # Generate from intent.examples
            for example in skill.intent.examples:
                case_counter += 1
                paraphrases = self._generate_paraphrases(example, skill.intent.keywords)
                cases.append(
                    BenchmarkCase(
                        id=f"route-auto-{case_counter:03d}",
                        input=example,
                        expected_skill=skill.name,
                        expected_execution_mode=exec_mode,
                        expected_complexity=complexity,
                        category="routing",
                        subcategory="keyword_match",
                        paraphrases=paraphrases,
                        tags=skill.intent.keywords[:3],
                    )
                )

            # Generate from intent.keywords (one case per keyword)
            for keyword in skill.intent.keywords:
                case_counter += 1
                query = (
                    f"帮我{keyword}"
                    if any("\u4e00" <= c <= "\u9fff" for c in keyword)
                    else f"Help me {keyword}"
                )
                cases.append(
                    BenchmarkCase(
                        id=f"route-kw-auto-{case_counter:03d}",
                        input=query,
                        expected_skill=skill.name,
                        expected_execution_mode=exec_mode,
                        expected_complexity=complexity,
                        category="routing",
                        subcategory="keyword_match",
                        tags=[keyword],
                    )
                )

        return cases

    def generate_execution_benchmarks(self) -> list[BenchmarkCase]:
        """Generate execution mode benchmark cases."""
        skills = self.load_skills()
        cases: list[BenchmarkCase] = []
        case_counter = 0

        # Group skills by execution mode
        mode_groups: dict[str, list[SkillConfig]] = {}
        for skill in skills:
            mode = self._get_effective_execution_mode(skill)
            mode_groups.setdefault(mode, []).append(skill)

        for mode, group in mode_groups.items():
            complexity = EXECUTION_MODE_TO_COMPLEXITY.get(mode, "low")
            for skill in group[:2]:  # Max 2 skills per mode
                if skill.intent.examples:
                    case_counter += 1
                    cases.append(
                        BenchmarkCase(
                            id=f"exec-auto-{case_counter:03d}",
                            input=skill.intent.examples[0],
                            expected_skill=skill.name,
                            expected_execution_mode=mode,
                            expected_complexity=complexity,
                            category="execution",
                            subcategory=f"{mode}_mode",
                            paraphrases=skill.intent.examples[1:2],
                            tags=[mode],
                        )
                    )

        return cases

    def generate_team_benchmarks(self) -> list[BenchmarkCase]:
        """Generate team collaboration benchmark cases."""
        skills = self.load_skills()
        cases: list[BenchmarkCase] = []
        case_counter = 0

        # High-complexity skills suitable for team collaboration
        high_complexity_skills = [
            s
            for s in skills
            if EXECUTION_MODE_TO_COMPLEXITY.get(self._get_effective_execution_mode(s), "low")
            == "high"
        ]

        if len(high_complexity_skills) >= 2:
            skill_a, skill_b = high_complexity_skills[0], high_complexity_skills[1]
            case_counter += 1
            cases.append(
                BenchmarkCase(
                    id=f"team-auto-{case_counter:03d}",
                    input=f"@team:{skill_a.name},{skill_b.name} 协作完成复杂分析任务",
                    expected_execution_mode="react",
                    expected_complexity="high",
                    category="team",
                    subcategory="explicit_team",
                    paraphrases=[
                        f"需要{skill_a.name}和{skill_b.name}协作分析",
                        f"组建团队：{skill_a.name} + {skill_b.name}",
                    ],
                    tags=["team", skill_a.name, skill_b.name],
                )
            )

        # Complexity-triggered team
        if high_complexity_skills:
            skill = high_complexity_skills[0]
            case_counter += 1
            cases.append(
                BenchmarkCase(
                    id=f"team-complexity-{case_counter:03d}",
                    input=f"深度{skill.intent.keywords[0] if skill.intent.keywords else '分析'}并生成详细报告",
                    expected_execution_mode="react",
                    expected_complexity="high",
                    category="team",
                    subcategory="complexity_trigger",
                    paraphrases=[
                        f"全面{skill.intent.keywords[0] if skill.intent.keywords else '分析'}并输出报告",
                    ],
                    tags=["team", "complexity"],
                )
            )

        return cases

    def generate_semantic_benchmarks(self) -> list[BenchmarkCase]:
        """Generate semantic router specific benchmark cases."""
        skills = self.load_skills()
        cases: list[BenchmarkCase] = []
        case_counter = 0

        for skill in skills:
            if not skill.intent.description:
                continue
            case_counter += 1
            # Use description as input (tests semantic matching, not keyword matching)
            cases.append(
                BenchmarkCase(
                    id=f"semantic-auto-{case_counter:03d}",
                    input=skill.intent.description,
                    expected_skill=skill.name,
                    expected_execution_mode=self._get_effective_execution_mode(skill),
                    expected_complexity=EXECUTION_MODE_TO_COMPLEXITY.get(
                        self._get_effective_execution_mode(skill), "low"
                    ),
                    category="semantic_router",
                    subcategory="description_match",
                    tags=["semantic", skill.name],
                )
            )

        return cases

    def generate_all(self) -> list[BenchmarkCase]:
        """Generate all auto-generated benchmark cases."""
        cases: list[BenchmarkCase] = []
        cases.extend(self.generate_routing_benchmarks())
        cases.extend(self.generate_execution_benchmarks())
        cases.extend(self.generate_team_benchmarks())
        cases.extend(self.generate_semantic_benchmarks())
        return cases

    def get_skill_names(self) -> set[str]:
        """Get all skill names from configs."""
        return {s.name for s in self.load_skills()}


# ═══════════════════════════════════════════════════════════════════════════
# Singleton for reuse
# ═══════════════════════════════════════════════════════════════════════════

_generator: BenchmarkGenerator | None = None


def get_generator() -> BenchmarkGenerator:
    """Get or create the singleton BenchmarkGenerator."""
    global _generator
    if _generator is None:
        _generator = BenchmarkGenerator()
    return _generator
