"""Test diff mode functionality."""

from pathlib import Path

from apiposture.core.models.endpoint import Endpoint
from apiposture.core.models.enums import EndpointType, Framework, HttpMethod, Severity
from apiposture.core.models.finding import Finding
from apiposture.core.models.scan_result import ScanResult

from apiposture_pro.features.diff_mode.analyzer import DiffAnalyzer


def test_diff_analyzer_initialization() -> None:
    """Test diff analyzer can be initialized."""
    analyzer = DiffAnalyzer()
    assert analyzer is not None


def test_diff_no_changes() -> None:
    """Test diff with identical scan results."""
    # Create a minimal endpoint for the finding
    endpoint = Endpoint(
        route="/test",
        methods=[HttpMethod.GET],
        file_path=Path("test.py"),
        line_number=5,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="test_func",
    )

    # Create identical results
    finding = Finding(
        rule_id="AP001",
        rule_name="Test Finding",
        severity=Severity.HIGH,
        message="Test",
        endpoint=endpoint,
        recommendation="Fix it",
    )

    baseline = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[finding])
    current = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[finding])

    analyzer = DiffAnalyzer()
    result = analyzer.compare(baseline, current)

    assert len(result.new_findings) == 0
    assert len(result.resolved_findings) == 0
    assert len(result.unchanged_findings) == 1
    assert not result.has_regressions


def test_diff_new_findings() -> None:
    """Test diff detects new findings."""
    baseline = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[])

    endpoint = Endpoint(
        route="/test",
        methods=[HttpMethod.GET],
        file_path=Path("test.py"),
        line_number=10,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="test_func",
    )

    new_finding = Finding(
        rule_id="AP002",
        rule_name="New Finding",
        severity=Severity.CRITICAL,
        message="New issue",
        endpoint=endpoint,
        recommendation="Fix urgently",
    )
    current = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[new_finding])

    analyzer = DiffAnalyzer()
    result = analyzer.compare(baseline, current)

    assert len(result.new_findings) == 1
    assert result.new_findings[0].rule_id == "AP002"
    assert len(result.resolved_findings) == 0
    assert result.has_regressions  # CRITICAL is a regression
    assert result.regression_count == 1


def test_diff_resolved_findings() -> None:
    """Test diff detects resolved findings."""
    endpoint = Endpoint(
        route="/test",
        methods=[HttpMethod.GET],
        file_path=Path("test.py"),
        line_number=15,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="test_func",
    )

    old_finding = Finding(
        rule_id="AP003",
        rule_name="Old Finding",
        severity=Severity.MEDIUM,
        message="Fixed issue",
        endpoint=endpoint,
        recommendation="Already fixed",
    )
    baseline = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[old_finding])

    current = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[])

    analyzer = DiffAnalyzer()
    result = analyzer.compare(baseline, current)

    assert len(result.new_findings) == 0
    assert len(result.resolved_findings) == 1
    assert result.resolved_findings[0].rule_id == "AP003"
    assert not result.has_regressions


def test_diff_endpoint_changes() -> None:
    """Test diff detects endpoint changes."""
    baseline_ep = Endpoint(
        route="/api/users",
        methods=[HttpMethod.GET],
        file_path=Path("api.py"),
        line_number=10,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="get_users",
    )
    baseline = ScanResult(scan_path=Path("/test"), endpoints=[baseline_ep], findings=[])

    current_ep1 = Endpoint(
        route="/api/users",
        methods=[HttpMethod.GET],
        file_path=Path("api.py"),
        line_number=10,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="get_users",
    )
    current_ep2 = Endpoint(
        route="/api/users",
        methods=[HttpMethod.POST],
        file_path=Path("api.py"),
        line_number=20,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="create_user",
    )
    current = ScanResult(scan_path=Path("/test"), endpoints=[current_ep1, current_ep2], findings=[])

    analyzer = DiffAnalyzer()
    result = analyzer.compare(baseline, current)

    assert len(result.new_endpoints) == 1
    assert "POST /api/users" in result.new_endpoints or "HttpMethod.POST /api/users" in result.new_endpoints
    assert len(result.removed_endpoints) == 0


def test_diff_removed_endpoints() -> None:
    """Test diff detects removed endpoints."""
    baseline_ep1 = Endpoint(
        route="/api/users",
        methods=[HttpMethod.GET],
        file_path=Path("api.py"),
        line_number=10,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="get_users",
    )
    baseline_ep2 = Endpoint(
        route="/api/users/{id}",
        methods=[HttpMethod.DELETE],
        file_path=Path("api.py"),
        line_number=20,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="delete_user",
    )
    baseline = ScanResult(
        scan_path=Path("/test"), endpoints=[baseline_ep1, baseline_ep2], findings=[]
    )

    current_ep = Endpoint(
        route="/api/users",
        methods=[HttpMethod.GET],
        file_path=Path("api.py"),
        line_number=10,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="get_users",
    )
    current = ScanResult(scan_path=Path("/test"), endpoints=[current_ep], findings=[])

    analyzer = DiffAnalyzer()
    result = analyzer.compare(baseline, current)

    assert len(result.new_endpoints) == 0
    assert len(result.removed_endpoints) == 1


def test_diff_regression_detection() -> None:
    """Test regression detection for critical/high findings."""
    baseline = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[])

    endpoint = Endpoint(
        route="/test",
        methods=[HttpMethod.GET],
        file_path=Path("test.py"),
        line_number=25,
        framework=Framework.FASTAPI,
        endpoint_type=EndpointType.ROUTER,
        function_name="test_func",
    )

    critical_finding = Finding(
        rule_id="AP004",
        rule_name="Critical Issue",
        severity=Severity.CRITICAL,
        message="Very bad",
        endpoint=endpoint,
        recommendation="Fix now",
    )
    high_finding = Finding(
        rule_id="AP005",
        rule_name="High Issue",
        severity=Severity.HIGH,
        message="Bad",
        endpoint=endpoint,
        recommendation="Fix soon",
    )
    medium_finding = Finding(
        rule_id="AP006",
        rule_name="Medium Issue",
        severity=Severity.MEDIUM,
        message="Not great",
        endpoint=endpoint,
        recommendation="Fix eventually",
    )

    current = ScanResult(
        scan_path=Path("/test"),
        endpoints=[],
        findings=[critical_finding, high_finding, medium_finding],
    )

    analyzer = DiffAnalyzer()
    result = analyzer.compare(baseline, current)

    assert result.has_regressions
    assert result.regression_count == 2  # Only CRITICAL and HIGH count as regressions


def test_diff_summary() -> None:
    """Test diff result summary generation."""
    baseline = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[])
    current = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[])

    analyzer = DiffAnalyzer()
    result = analyzer.compare(baseline, current)

    summary = result.summary
    assert "Baseline: 0 findings" in summary
    assert "Current: 0 findings" in summary
    assert "New findings:" in summary
    assert "Resolved findings:" in summary
