"""Analyzer for comparing scan results."""

from apiposture.core.models.scan_result import ScanResult

from apiposture_pro.features.diff_mode.models import DiffResult


class DiffAnalyzer:
    """Analyzes differences between two scan results."""

    def __init__(self) -> None:
        """Initialize diff analyzer."""
        self.regression_severities = {"critical", "high"}

    def compare(self, baseline: ScanResult, current: ScanResult) -> DiffResult:
        """
        Compare two scan results and identify changes.

        Args:
            baseline: Baseline scan result
            current: Current scan result

        Returns:
            DiffResult with detected changes
        """
        result = DiffResult(
            baseline_scan_count=len(baseline.findings),
            current_scan_count=len(current.findings),
        )

        # Compare findings
        self._compare_findings(baseline, current, result)

        # Compare endpoints
        self._compare_endpoints(baseline, current, result)

        # Detect regressions
        self._detect_regressions(result)

        return result

    def _compare_findings(
        self, baseline: ScanResult, current: ScanResult, result: DiffResult
    ) -> None:
        """Compare findings between baseline and current scans."""
        # Create finding signatures for comparison
        baseline_sigs = {self._finding_signature(f): f for f in baseline.findings}
        current_sigs = {self._finding_signature(f): f for f in current.findings}

        # Find new findings
        for sig, finding in current_sigs.items():
            if sig not in baseline_sigs:
                result.new_findings.append(finding)

        # Find resolved findings
        for sig, finding in baseline_sigs.items():
            if sig not in current_sigs:
                result.resolved_findings.append(finding)

        # Find unchanged findings
        for sig in baseline_sigs:
            if sig in current_sigs:
                result.unchanged_findings.append(current_sigs[sig])

    def _compare_endpoints(
        self, baseline: ScanResult, current: ScanResult, result: DiffResult
    ) -> None:
        """Compare endpoints between baseline and current scans."""
        baseline_eps = {
            f"{method} {ep.route}"
            for ep in baseline.endpoints
            if hasattr(ep, "route") and hasattr(ep, "methods")
            for method in ep.methods
        }
        current_eps = {
            f"{method} {ep.route}"
            for ep in current.endpoints
            if hasattr(ep, "route") and hasattr(ep, "methods")
            for method in ep.methods
        }

        # New endpoints
        result.new_endpoints = sorted(current_eps - baseline_eps)

        # Removed endpoints
        result.removed_endpoints = sorted(baseline_eps - current_eps)

    def _detect_regressions(self, result: DiffResult) -> None:
        """Detect if there are any security regressions."""
        # Count new critical/high findings as regressions
        # severity is an enum, so we need to check the value
        regression_count = sum(
            1 for f in result.new_findings if f.severity.value in self.regression_severities
        )

        result.has_regressions = regression_count > 0
        result.regression_count = regression_count

    def _finding_signature(self, finding) -> str:
        """
        Generate a unique signature for a finding.

        Args:
            finding: Finding to generate signature for

        Returns:
            Unique signature string
        """
        # Use rule_id, severity, and endpoint info to create signature
        endpoint_sig = ""
        if hasattr(finding, "endpoint") and finding.endpoint:
            endpoint_sig = f"{finding.endpoint.route}:{finding.endpoint.line_number}"

        parts = [
            finding.rule_id,
            str(finding.severity),
            endpoint_sig,
        ]
        return "|".join(str(p) for p in parts)
