"""ASV benchmarks for diff review artifact building and serialization.

Measures the performance of:
- DiffBuilder.build() with various changeset sizes
- DiffSerializer.to_plain() / to_json() / to_rich()
- Rename detection with content hash matching
- ReviewArtifact and DiffEntry construction
"""

from __future__ import annotations

import sys
from pathlib import Path

try:
    from cleveragents.domain.models.core.change import (
        ChangeEntry,
        ChangeOperation,
        SpecChangeSet,
    )
    from cleveragents.domain.models.core.diff_review import (
        DiffBuilder,
        DiffEntry,
        DiffSerializer,
        ResourceDiffGroup,
        ReviewArtifact,
    )
except ModuleNotFoundError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
    from cleveragents.domain.models.core.change import (
        ChangeEntry,
        ChangeOperation,
        SpecChangeSet,
    )
    from cleveragents.domain.models.core.diff_review import (
        DiffBuilder,
        DiffEntry,
        DiffSerializer,
        ResourceDiffGroup,
        ReviewArtifact,
    )


def _make_changeset(
    n_entries: int = 10,
) -> tuple[SpecChangeSet, dict[str, str], dict[str, str]]:
    """Create a changeset with n_entries MODIFY entries and content maps."""
    cs = SpecChangeSet(plan_id="BENCH-PLAN")
    before_map: dict[str, str] = {}
    after_map: dict[str, str] = {}
    for i in range(n_entries):
        path = f"src/module_{i:04d}.py"
        cs.add_change(
            ChangeEntry(
                plan_id="BENCH-PLAN",
                resource_id=f"RES{i % 5:03d}",
                tool_name="builtin/bench-tool",
                operation=ChangeOperation.MODIFY,
                path=path,
                before_hash=f"before-{i}",
                after_hash=f"after-{i}",
            )
        )
        before_map[path] = f"# module {i}\nx = {i}\n"
        after_map[path] = f"# module {i}\nx = {i + 1}\ny = {i}\n"
    return cs, before_map, after_map


class DiffBuildSuite:
    """Benchmark DiffBuilder.build() with various changeset sizes."""

    def setup(self) -> None:
        """Prepare changesets of different sizes."""
        self.builder = DiffBuilder()
        self.cs_small, self.bm_small, self.am_small = _make_changeset(5)
        self.cs_medium, self.bm_medium, self.am_medium = _make_changeset(50)
        self.cs_large, self.bm_large, self.am_large = _make_changeset(200)

    def time_build_small(self) -> None:
        """Benchmark building artifact from 5-entry changeset."""
        self.builder.build(
            self.cs_small,
            before_contents=self.bm_small,
            after_contents=self.am_small,
        )

    def time_build_medium(self) -> None:
        """Benchmark building artifact from 50-entry changeset."""
        self.builder.build(
            self.cs_medium,
            before_contents=self.bm_medium,
            after_contents=self.am_medium,
        )

    def time_build_large(self) -> None:
        """Benchmark building artifact from 200-entry changeset."""
        self.builder.build(
            self.cs_large,
            before_contents=self.bm_large,
            after_contents=self.am_large,
        )


class DiffSerializationSuite:
    """Benchmark DiffSerializer output formats."""

    def setup(self) -> None:
        """Build an artifact to serialize."""
        cs, bm, am = _make_changeset(20)
        builder = DiffBuilder()
        self.artifact = builder.build(cs, before_contents=bm, after_contents=am)

    def time_to_plain(self) -> None:
        """Benchmark plain text serialization."""
        DiffSerializer.to_plain(self.artifact)

    def time_to_json(self) -> None:
        """Benchmark JSON serialization."""
        DiffSerializer.to_json(self.artifact)

    def time_to_rich(self) -> None:
        """Benchmark rich text serialization."""
        DiffSerializer.to_rich(self.artifact)


class DiffRenameSuite:
    """Benchmark rename detection with content hash matching."""

    def setup(self) -> None:
        """Prepare a changeset with rename pairs."""
        self.builder = DiffBuilder()
        self.cs = SpecChangeSet(plan_id="BENCH-PLAN")
        for i in range(20):
            self.cs.add_change(
                ChangeEntry(
                    plan_id="BENCH-PLAN",
                    resource_id="RES001",
                    tool_name="builtin/bench-tool",
                    operation=ChangeOperation.DELETE,
                    path=f"old/module_{i:04d}.py",
                    before_hash=f"hash-{i}",
                )
            )
            self.cs.add_change(
                ChangeEntry(
                    plan_id="BENCH-PLAN",
                    resource_id="RES001",
                    tool_name="builtin/bench-tool",
                    operation=ChangeOperation.CREATE,
                    path=f"new/module_{i:04d}.py",
                    after_hash=f"hash-{i}",
                )
            )

    def time_rename_detection(self) -> None:
        """Benchmark rename detection for 20 pairs."""
        self.builder.build(self.cs)


class DiffModelSuite:
    """Benchmark DiffEntry and ReviewArtifact construction."""

    def time_diff_entry_construction(self) -> None:
        """Benchmark creating a DiffEntry."""
        DiffEntry(
            resource_id="RES001",
            resource_name="test-resource",
            path="src/main.py",
            change_type="modify",
            diff_text="--- a/src/main.py\n+++ b/src/main.py\n",
        )

    def time_resource_diff_group_construction(self) -> None:
        """Benchmark creating a ResourceDiffGroup."""
        ResourceDiffGroup(
            resource_id="RES001",
            resource_name="test-resource",
            entries=[
                DiffEntry(
                    resource_id="RES001",
                    path="a.py",
                    change_type="create",
                ),
                DiffEntry(
                    resource_id="RES001",
                    path="b.py",
                    change_type="modify",
                ),
            ],
        )

    def time_review_artifact_construction(self) -> None:
        """Benchmark creating a ReviewArtifact."""
        ReviewArtifact(
            plan_id="PLAN001",
            changeset_id="CS001",
            total_changes=5,
        )
