"""Test risk scoring functionality."""

from pathlib import Path

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

from apiposture_pro.features.risk_scoring.calculator import RiskScoreCalculator
from apiposture_pro.features.risk_scoring.models import RiskLevel, RiskScore


def test_risk_score_calculator_initialization() -> None:
    """Test risk score calculator can be initialized."""
    calculator = RiskScoreCalculator()
    assert calculator is not None


def test_calculate_no_findings_no_endpoints() -> None:
    """Test risk score with no findings and no endpoints."""
    calculator = RiskScoreCalculator()
    result = ScanResult(scan_path=Path("/test"), endpoints=[], findings=[])

    score = calculator.calculate(result)

    assert score.total_score == 0
    assert score.risk_level == RiskLevel.MINIMAL
    assert score.findings_score == 0
    assert score.exposure_score == 0
    assert score.surface_area_score == 0


def test_calculate_with_critical_findings() -> None:
    """Test risk score with critical findings."""
    calculator = RiskScoreCalculator()

    # Create critical 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",
    )

    findings = [
        Finding(
            rule_id=f"AP00{i}",
            rule_name=f"Critical Finding {i}",
            severity=Severity.CRITICAL,
            message="Critical issue",
            endpoint=endpoint,
            recommendation="Fix immediately",
        )
        for i in range(3)
    ]

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

    score = calculator.calculate(result)

    assert score.total_score > 0
    assert score.findings_score > 0
    assert score.critical_findings == 3
    # With critical findings, should be at least MEDIUM risk
    assert score.risk_level in [RiskLevel.MEDIUM, RiskLevel.HIGH, RiskLevel.CRITICAL]


def test_calculate_with_mixed_severity_findings() -> None:
    """Test risk score with mixed severity findings."""
    calculator = RiskScoreCalculator()

    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",
    )

    findings = [
        Finding(
            rule_id="AP001",
            rule_name="Critical",
            severity=Severity.CRITICAL,
            message="Bad",
            endpoint=endpoint,
            recommendation="Fix",
        ),
        Finding(
            rule_id="AP002",
            rule_name="High",
            severity=Severity.HIGH,
            message="Bad",
            endpoint=endpoint,
            recommendation="Fix",
        ),
        Finding(
            rule_id="AP003",
            rule_name="Medium",
            severity=Severity.MEDIUM,
            message="Not great",
            endpoint=endpoint,
            recommendation="Fix",
        ),
    ]

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

    score = calculator.calculate(result)

    assert score.total_findings == 3
    assert score.critical_findings == 1
    assert score.high_findings == 1
    # Score should reflect weighted severity
    assert score.findings_score > 0


def test_calculate_exposure_score_all_public() -> None:
    """Test exposure score with all public endpoints."""
    calculator = RiskScoreCalculator()

    # Create public endpoints
    endpoints = [
        Endpoint(
            route=f"/api/endpoint{i}",
            methods=[HttpMethod.GET],
            file_path=Path("api.py"),
            line_number=10 + i,
            framework=Framework.FASTAPI,
            endpoint_type=EndpointType.ROUTER,
            function_name=f"endpoint{i}",
            classification=SecurityClassification.PUBLIC,
        )
        for i in range(5)
    ]

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

    score = calculator.calculate(result)

    # All endpoints are public, so exposure score should be maximum
    assert score.exposure_score == calculator.MAX_EXPOSURE_SCORE
    assert score.public_endpoints == 5
    assert score.total_endpoints == 5


def test_calculate_exposure_score_mixed() -> None:
    """Test exposure score with mixed public/private endpoints."""
    calculator = RiskScoreCalculator()

    # Create mixed endpoints
    public_endpoints = [
        Endpoint(
            route="/public",
            methods=[HttpMethod.GET],
            file_path=Path("api.py"),
            line_number=10,
            framework=Framework.FASTAPI,
            endpoint_type=EndpointType.ROUTER,
            function_name="public",
            classification=SecurityClassification.PUBLIC,
        )
    ]

    private_endpoints = [
        Endpoint(
            route="/private",
            methods=[HttpMethod.GET],
            file_path=Path("api.py"),
            line_number=20,
            framework=Framework.FASTAPI,
            endpoint_type=EndpointType.ROUTER,
            function_name="private",
            classification=SecurityClassification.AUTHENTICATED,
        )
    ]

    result = ScanResult(
        scan_path=Path("/test"),
        endpoints=public_endpoints + private_endpoints,
        findings=[],
    )

    score = calculator.calculate(result)

    # 50% public, so exposure score should be half of max
    assert score.exposure_score == calculator.MAX_EXPOSURE_SCORE // 2
    assert score.public_endpoints == 1
    assert score.total_endpoints == 2


def test_calculate_surface_area_score() -> None:
    """Test surface area score scales with endpoint count."""
    calculator = RiskScoreCalculator()

    # Create many endpoints
    endpoints = [
        Endpoint(
            route=f"/api/endpoint{i}",
            methods=[HttpMethod.GET],
            file_path=Path("api.py"),
            line_number=10 + i,
            framework=Framework.FASTAPI,
            endpoint_type=EndpointType.ROUTER,
            function_name=f"endpoint{i}",
        )
        for i in range(50)
    ]

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

    score = calculator.calculate(result)

    # With 50 endpoints, surface area score should be significant
    assert score.surface_area_score > 0
    assert score.total_endpoints == 50


def test_risk_level_classification() -> None:
    """Test risk level classification thresholds."""
    assert RiskScore.get_risk_level(0) == RiskLevel.MINIMAL
    assert RiskScore.get_risk_level(10) == RiskLevel.LOW
    assert RiskScore.get_risk_level(24) == RiskLevel.LOW
    assert RiskScore.get_risk_level(25) == RiskLevel.MEDIUM
    assert RiskScore.get_risk_level(49) == RiskLevel.MEDIUM
    assert RiskScore.get_risk_level(50) == RiskLevel.HIGH
    assert RiskScore.get_risk_level(74) == RiskLevel.HIGH
    assert RiskScore.get_risk_level(75) == RiskLevel.CRITICAL
    assert RiskScore.get_risk_level(100) == RiskLevel.CRITICAL


def test_risk_score_color() -> None:
    """Test risk score color property."""
    score = RiskScore(
        total_score=75,
        risk_level=RiskLevel.CRITICAL,
        findings_score=40,
        exposure_score=25,
        surface_area_score=10,
    )

    assert score.color == "red"


def test_risk_score_summary() -> None:
    """Test risk score summary generation."""
    score = RiskScore(
        total_score=65,
        risk_level=RiskLevel.HIGH,
        findings_score=35,
        exposure_score=20,
        surface_area_score=10,
        total_findings=15,
        critical_findings=2,
        high_findings=3,
        total_endpoints=20,
        public_endpoints=15,
    )

    summary = score.summary

    assert "65/100" in summary
    assert "HIGH" in summary
    assert "35/50" in summary
    assert "20/30" in summary
    assert "10/20" in summary
    assert "15" in summary  # total findings


def test_findings_score_logarithmic_scale() -> None:
    """Test that findings score uses logarithmic scale to prevent saturation."""
    calculator = RiskScoreCalculator()

    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",
    )

    # Create 10 critical findings
    findings_10 = [
        Finding(
            rule_id=f"AP{i:03d}",
            rule_name=f"Finding {i}",
            severity=Severity.CRITICAL,
            message="Test",
            endpoint=endpoint,
            recommendation="Fix",
        )
        for i in range(10)
    ]

    result_10 = ScanResult(
        scan_path=Path("/test"), endpoints=[endpoint], findings=findings_10
    )
    score_10 = calculator.calculate(result_10)

    # Create 20 critical findings (double)
    findings_20 = [
        Finding(
            rule_id=f"AP{i:03d}",
            rule_name=f"Finding {i}",
            severity=Severity.CRITICAL,
            message="Test",
            endpoint=endpoint,
            recommendation="Fix",
        )
        for i in range(20)
    ]

    result_20 = ScanResult(
        scan_path=Path("/test"), endpoints=[endpoint], findings=findings_20
    )
    score_20 = calculator.calculate(result_20)

    # Score should increase, but not double (due to logarithmic scale)
    assert score_20.findings_score > score_10.findings_score
    assert score_20.findings_score < score_10.findings_score * 2


def test_calculate_with_info_findings_only() -> None:
    """Test risk score with only INFO findings."""
    calculator = RiskScoreCalculator()

    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",
        classification=SecurityClassification.AUTHENTICATED,
    )

    findings = [
        Finding(
            rule_id=f"AP00{i}",
            rule_name=f"Info {i}",
            severity=Severity.INFO,
            message="Info",
            endpoint=endpoint,
            recommendation="Consider",
        )
        for i in range(5)
    ]

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

    score = calculator.calculate(result)

    # INFO findings should contribute minimally to score
    assert score.total_score < 25
    assert score.risk_level in [RiskLevel.MINIMAL, RiskLevel.LOW]
