"""Multi-session regression detection.

Compares insights across sessions to detect regressions,
new issues, and latency trend degradation.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any, Dict, List, Set

if TYPE_CHECKING:
    from autodebug.detection.transcript_analyzer import Transcript, TranscriptInsight


@dataclass
class Regression:
    """A detected regression between two sessions."""
    category: str
    severity: int
    description: str
    evidence: Dict[str, Any] = field(default_factory=dict)
    is_new_issue: bool = False
    is_latency_regression: bool = False


@dataclass
class RegressionReport:
    """Complete regression analysis between sessions."""
    regressions: List[Regression] = field(default_factory=list)
    resolved_issues: List[str] = field(default_factory=list)
    unchanged_issues: List[str] = field(default_factory=list)

    @property
    def has_regressions(self) -> bool:
        return len(self.regressions) > 0


class RegressionDetector:
    """Compare insights across sessions to detect regressions."""

    def __init__(self, latency_regression_threshold: float = 1.5):
        """Args:
            latency_regression_threshold: multiplier above which latency is flagged (1.5 = 50% slower)
        """
        self.latency_regression_threshold = latency_regression_threshold

    def compare(
        self,
        current_insights: List[TranscriptInsight],
        baseline_insights: List[TranscriptInsight],
    ) -> RegressionReport:
        """Compare current session insights against a baseline (previous passing run)."""
        current_keys = self._insight_keys(current_insights)
        baseline_keys = self._insight_keys(baseline_insights)

        new_keys = current_keys - baseline_keys
        resolved_keys = baseline_keys - current_keys
        unchanged_keys = current_keys & baseline_keys

        regressions: List[Regression] = []

        # New issues = regressions
        current_by_key = {self._key(i): i for i in current_insights}
        for key in new_keys:
            insight = current_by_key.get(key)
            if insight:
                regressions.append(
                    Regression(
                        category=f"new_{insight.category}",
                        severity=insight.severity,
                        description=f"New issue: {insight.description}",
                        evidence=insight.evidence,
                        is_new_issue=True,
                    )
                )

        # Check latency regressions
        regressions.extend(self._check_latency_regressions(
            current_insights, baseline_insights
        ))

        return RegressionReport(
            regressions=regressions,
            resolved_issues=[k for k in sorted(resolved_keys)],
            unchanged_issues=[k for k in sorted(unchanged_keys)],
        )

    def compare_transcripts(
        self,
        current: Transcript,
        baseline: Transcript,
    ) -> RegressionReport:
        """Compare two transcripts for latency regressions at the endpoint level."""
        regressions: List[Regression] = []

        # Compare HTTP endpoint latencies
        current_http = self._endpoint_latencies(current.http_records, "http")
        baseline_http = self._endpoint_latencies(baseline.http_records, "http")
        regressions.extend(self._compare_latencies(current_http, baseline_http, "http"))

        # Compare SQL query latencies
        current_sql = self._endpoint_latencies(current.sql_records, "sql")
        baseline_sql = self._endpoint_latencies(baseline.sql_records, "sql")
        regressions.extend(self._compare_latencies(current_sql, baseline_sql, "sql"))

        # Compare Redis latencies
        current_redis = self._endpoint_latencies(
            getattr(current, "redis_records", []), "redis"
        )
        baseline_redis = self._endpoint_latencies(
            getattr(baseline, "redis_records", []), "redis"
        )
        regressions.extend(self._compare_latencies(current_redis, baseline_redis, "redis"))

        return RegressionReport(regressions=regressions)

    def _insight_keys(self, insights: List[TranscriptInsight]) -> Set[str]:
        return {self._key(i) for i in insights}

    def _key(self, insight: TranscriptInsight) -> str:
        import hashlib
        desc_hash = hashlib.sha256(insight.description.encode()).hexdigest()[:16]
        return f"{insight.category}:{desc_hash}"

    def _endpoint_latencies(self, records: List[Any], op_type: str) -> Dict[str, List[float]]:
        latencies: Dict[str, List[float]] = {}
        for r in records:
            duration = getattr(r, "duration_ms", 0)
            if duration <= 0:
                continue
            if op_type == "http":
                key = getattr(r, "url_canonical", "unknown")
            elif op_type == "sql":
                key = getattr(r, "sql_canonical", "")[:100]
            elif op_type == "redis":
                key = f"{getattr(r, 'command', '')}:{getattr(r, 'key', '')}"
            else:
                key = "unknown"
            latencies.setdefault(key, []).append(duration)
        return latencies

    def _compare_latencies(
        self,
        current: Dict[str, List[float]],
        baseline: Dict[str, List[float]],
        op_type: str,
    ) -> List[Regression]:
        regressions: List[Regression] = []

        for endpoint, cur_durations in current.items():
            base_durations = baseline.get(endpoint)
            if not base_durations:
                continue

            cur_avg = sum(cur_durations) / len(cur_durations)
            base_avg = sum(base_durations) / len(base_durations)

            if base_avg > 0 and cur_avg > base_avg * self.latency_regression_threshold:
                ratio = cur_avg / base_avg
                regressions.append(
                    Regression(
                        category=f"{op_type}_latency_regression",
                        severity=4 if ratio > 2.0 else 3,
                        description=f"{op_type.upper()} latency regression for {endpoint}: {cur_avg:.0f}ms vs baseline {base_avg:.0f}ms ({ratio:.1f}x slower)",
                        evidence={
                            "endpoint": endpoint,
                            "current_avg_ms": round(cur_avg, 1),
                            "baseline_avg_ms": round(base_avg, 1),
                            "regression_ratio": round(ratio, 2),
                            "operation_type": op_type,
                        },
                        is_latency_regression=True,
                    )
                )

        return regressions

    def _check_latency_regressions(
        self,
        current_insights: List[TranscriptInsight],
        baseline_insights: List[TranscriptInsight],
    ) -> List[Regression]:
        """Check for severity escalation in timing-related insights."""
        regressions: List[Regression] = []

        # Group by category
        current_by_cat = {}
        for i in current_insights:
            current_by_cat.setdefault(i.category, []).append(i)

        baseline_by_cat = {}
        for i in baseline_insights:
            baseline_by_cat.setdefault(i.category, []).append(i)

        timing_cats = {"slow_query", "slow_http", "slow_redis", "slow_grpc",
                       "timeout_risk", "latency_spike"}

        for cat in timing_cats:
            cur_list = current_by_cat.get(cat, [])
            base_list = baseline_by_cat.get(cat, [])

            if len(cur_list) > len(base_list) + 2:
                regressions.append(
                    Regression(
                        category=f"{cat}_count_regression",
                        severity=3,
                        description=f"More {cat} issues: {len(cur_list)} vs baseline {len(base_list)}",
                        evidence={
                            "current_count": len(cur_list),
                            "baseline_count": len(base_list),
                        },
                        is_latency_regression=True,
                    )
                )

        return regressions
