"""ASV benchmarks for ACMS pipeline Phase 2 — Fragment Fusion components.

Measures the performance of:
- ContentHashDeduplicator with varying fragment counts
- MaxDepthResolver with varying fragment counts
- WeightedCompositeScorer with varying fragment counts
- GreedyKnapsackPacker with varying fragment counts and budgets
- ScoredFragment creation
"""

from __future__ import annotations

import importlib
import sys
from pathlib import Path
from typing import ClassVar

_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
    sys.path.insert(0, _SRC)

import cleveragents  # noqa: E402

importlib.reload(cleveragents)

from cleveragents.application.services.acms_phase2 import (  # noqa: E402
    ContentHashDeduplicator,
    GreedyKnapsackPacker,
    MaxDepthResolver,
    WeightedCompositeScorer,
)
from cleveragents.domain.models.core.context_fragment import (  # noqa: E402
    ContextBudget,
    ContextFragment,
    FragmentProvenance,
    ScoredFragment,
)

_DEFAULT_PROV = FragmentProvenance(resource_uri="bench://phase2")


def _make_fragments(n: int, *, unique_nodes: bool = True) -> list[ContextFragment]:
    """Create *n* fragments for benchmarks."""
    frags: list[ContextFragment] = []
    for i in range(n):
        node = f"bench://file{i}" if unique_nodes else "bench://same-node"
        frags.append(
            ContextFragment(
                uko_node=node,
                content=f"content-{i}",
                relevance_score=round(0.1 + (i % 10) * 0.09, 2),
                token_count=50 + (i % 5) * 10,
                detail_depth=i % 10,
                provenance=_DEFAULT_PROV,
            )
        )
    return frags


class ContentHashDeduplicatorSuite:
    """Benchmark ContentHashDeduplicator throughput."""

    params: ClassVar[list[int]] = [10, 100, 500]
    param_names: ClassVar[list[str]] = ["fragment_count"]

    def setup(self, n: int) -> None:
        self.dedup = ContentHashDeduplicator()
        # Half the fragments are duplicates
        base = _make_fragments(n // 2, unique_nodes=True)
        self.fragments = base + [
            ContextFragment(
                uko_node=f.uko_node,
                content=f.content,
                relevance_score=max(0.0, f.relevance_score - 0.1),
                token_count=f.token_count,
                detail_depth=f.detail_depth,
                provenance=_DEFAULT_PROV,
            )
            for f in base
        ]

    def time_deduplicate(self, n: int) -> None:
        self.dedup.deduplicate(self.fragments)


class MaxDepthResolverSuite:
    """Benchmark MaxDepthResolver throughput."""

    params: ClassVar[list[int]] = [10, 100, 500]
    param_names: ClassVar[list[str]] = ["fragment_count"]

    def setup(self, n: int) -> None:
        self.resolver = MaxDepthResolver()
        # Multiple depths per node
        self.fragments: list[ContextFragment] = []
        for i in range(n):
            node_idx = i % (n // 3 + 1)
            self.fragments.append(
                ContextFragment(
                    uko_node=f"bench://file{node_idx}",
                    content=f"content-{i}",
                    relevance_score=0.5,
                    token_count=50,
                    detail_depth=i % 10,
                    provenance=_DEFAULT_PROV,
                )
            )

    def time_resolve(self, n: int) -> None:
        self.resolver.resolve(self.fragments)


class WeightedCompositeScorerSuite:
    """Benchmark WeightedCompositeScorer throughput."""

    params: ClassVar[list[int]] = [10, 100, 500]
    param_names: ClassVar[list[str]] = ["fragment_count"]

    def setup(self, n: int) -> None:
        self.scorer = WeightedCompositeScorer()
        self.fragments = _make_fragments(n)

    def time_score(self, n: int) -> None:
        self.scorer.score(self.fragments)

    def time_score_detailed(self, n: int) -> None:
        self.scorer.score_detailed(self.fragments)


class GreedyKnapsackPackerSuite:
    """Benchmark GreedyKnapsackPacker throughput."""

    params: ClassVar[list[int]] = [10, 100, 500]
    param_names: ClassVar[list[str]] = ["fragment_count"]

    def setup(self, n: int) -> None:
        self.packer = GreedyKnapsackPacker()
        self.fragments = _make_fragments(n)
        # Budget that fits about half the fragments
        total = sum(f.token_count for f in self.fragments)
        self.budget = ContextBudget(max_tokens=total // 2, reserved_tokens=0)

    def time_pack(self, n: int) -> None:
        self.packer.pack(self.fragments, self.budget)


class ScoredFragmentSuite:
    """Benchmark ScoredFragment creation."""

    def setup(self) -> None:
        self.fragment = ContextFragment(
            uko_node="bench://file",
            content="benchmark content",
            token_count=10,
            provenance=_DEFAULT_PROV,
        )

    def time_scored_fragment_creation(self) -> None:
        ScoredFragment(
            fragment=self.fragment,
            composite_score=0.85,
            score_components={"relevance": 0.9, "hierarchy": 0.8},
        )
