"""Data models for benchmarking and performance measurement."""

from __future__ import annotations

import re
from typing import TYPE_CHECKING

import attrs

from codeflash_core import BenchmarkDetail, PrComment

if TYPE_CHECKING:
    from ..testing.models import TestResults

benchmark_context_cleaner = re.compile(r"[^a-zA-Z0-9_]+")


@attrs.frozen
class BenchmarkKey:
    """Identifies a benchmark by module path and function name."""

    module_path: str
    function_name: str

    def __str__(self) -> str:
        """Return module::function representation."""
        return f"{self.module_path}::{self.function_name}"


@attrs.frozen
class ProcessedBenchmarkInfo:
    """Container for benchmark performance details."""

    benchmark_details: tuple[BenchmarkDetail, ...]

    def to_string(self) -> str:
        """Return a human-readable multi-line summary."""
        if not self.benchmark_details:
            return ""
        result = "Benchmark Performance Details:\n"
        for detail in self.benchmark_details:
            result += detail.to_string() + "\n"
        return result


@attrs.frozen
class ConcurrencyMetrics:
    """Concurrency benchmark results for an async function."""

    sequential_time_ns: int
    concurrent_time_ns: int
    concurrency_factor: int
    concurrency_ratio: float


def get_function_alias(module: str, function_name: str) -> str:
    """Build a flattened alias from a dotted module path and function name."""
    return "_".join(module.split(".")) + "_" + function_name


def get_unique_test_name(
    module: str,
    function_name: str,
    benchmark_name: str,
    class_name: str | None = None,
) -> str:
    """Build a unique test name from module, function, and benchmark context."""
    clean_benchmark = benchmark_context_cleaner.sub("_", benchmark_name).strip(
        "_"
    )
    base_alias = get_function_alias(module, function_name)
    if class_name:
        class_alias = get_function_alias(module, class_name)
        return f"{class_alias}_{function_name}_{clean_benchmark}"
    return f"{base_alias}_{clean_benchmark}"


def build_pr_comment(  # noqa: PLR0913
    *,
    optimization_explanation: str,
    best_runtime: int,
    original_runtime: int,
    function_name: str,
    relative_file_path: str,
    speedup_x: str,
    speedup_pct: str,
    winning_behavior_test_results: TestResults,
    winning_benchmarking_test_results: TestResults,
    benchmark_details: tuple[BenchmarkDetail, ...] | None = None,
    original_async_throughput: int | None = None,
    best_async_throughput: int | None = None,
) -> PrComment:
    """Build a :class:`PrComment` from Python test results."""
    report_table: dict[str, dict[str, int]] = {}
    by_type = winning_behavior_test_results.get_test_pass_fail_report_by_type()
    for test_type, counts in by_type.items():
        name = test_type.to_name()
        if name:
            report_table[name] = counts

    return PrComment(
        optimization_explanation=optimization_explanation,
        best_runtime=best_runtime,
        original_runtime=original_runtime,
        function_name=function_name,
        relative_file_path=relative_file_path,
        speedup_x=speedup_x,
        speedup_pct=speedup_pct,
        loop_count=winning_benchmarking_test_results.number_of_loops(),
        report_table=report_table,
        benchmark_details=benchmark_details,
        original_async_throughput=original_async_throughput,
        best_async_throughput=best_async_throughput,
    )
