"""Test historical tracking 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.historical_tracking.store import HistoryStore


def test_history_store_initialization(temp_dir: Path) -> None:
    """Test history store can be initialized."""
    db_path = temp_dir / "test.db"
    HistoryStore(db_path=db_path)

    assert db_path.exists()


def test_save_scan(temp_dir: Path) -> None:
    """Test saving a scan to history."""
    db_path = temp_dir / "test.db"
    store = HistoryStore(db_path=db_path)

    # Create a minimal scan result
    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",
    )

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

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

    # Save scan
    scan_id = store.save_scan(result, duration_ms=1000, risk_score=75)

    assert scan_id > 0


def test_list_scans(temp_dir: Path) -> None:
    """Test listing scans."""
    db_path = temp_dir / "test.db"
    store = HistoryStore(db_path=db_path)

    # Create and save multiple scans
    for i in range(3):
        result = ScanResult(
            scan_path=Path(f"/test/project{i}"),
            endpoints=[],
            findings=[],
        )
        store.save_scan(result, duration_ms=1000)

    # List all scans
    scans = store.list_scans()
    assert len(scans) == 3


def test_list_scans_filtered_by_project(temp_dir: Path) -> None:
    """Test listing scans filtered by project."""
    db_path = temp_dir / "test.db"
    store = HistoryStore(db_path=db_path)

    # Create scans for different projects
    project_a = Path("/test/project_a")
    project_b = Path("/test/project_b")

    for _ in range(2):
        result = ScanResult(scan_path=project_a, endpoints=[], findings=[])
        store.save_scan(result)

    for _ in range(3):
        result = ScanResult(scan_path=project_b, endpoints=[], findings=[])
        store.save_scan(result)

    # List scans for project_a
    scans = store.list_scans(project_path=str(project_a))
    assert len(scans) == 2


def test_get_scan(temp_dir: Path) -> None:
    """Test getting a specific scan."""
    db_path = temp_dir / "test.db"
    store = HistoryStore(db_path=db_path)

    # Save a scan
    result = ScanResult(
        scan_path=Path("/test/project"),
        endpoints=[],
        findings=[],
    )
    scan_id = store.save_scan(result, duration_ms=1500, risk_score=50)

    # Get the scan
    scan = store.get_scan(scan_id)

    assert scan is not None
    assert scan.id == scan_id
    assert scan.scan_duration_ms == 1500
    assert scan.risk_score == 50


def test_get_scan_not_found(temp_dir: Path) -> None:
    """Test getting a nonexistent scan."""
    db_path = temp_dir / "test.db"
    store = HistoryStore(db_path=db_path)

    scan = store.get_scan(999)
    assert scan is None


def test_get_trend(temp_dir: Path) -> None:
    """Test getting trend data."""
    db_path = temp_dir / "test.db"
    store = HistoryStore(db_path=db_path)

    project_path = Path("/test/project")

    # Create scans over time
    for i in range(5):
        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{j}",
                rule_name=f"Finding {j}",
                severity=Severity.MEDIUM,
                message="Test",
                endpoint=endpoint,
                recommendation="Fix",
            )
            for j in range(i + 1)  # Increasing number of findings
        ]

        result = ScanResult(
            scan_path=project_path,
            endpoints=[endpoint],
            findings=findings,
        )
        store.save_scan(result, risk_score=10 * (i + 1))

    # Get trend
    trend = store.get_trend(str(project_path), days=30)

    assert len(trend) == 5
    # Check that findings are increasing
    findings_counts = [count for _, count, _ in trend]
    assert findings_counts == [1, 2, 3, 4, 5]


def test_cleanup(temp_dir: Path) -> None:
    """Test cleaning up old scans."""
    db_path = temp_dir / "test.db"
    store = HistoryStore(db_path=db_path)

    # Create a scan
    result = ScanResult(
        scan_path=Path("/test/project"),
        endpoints=[],
        findings=[],
    )
    store.save_scan(result)

    # Verify it exists
    scans = store.list_scans()
    assert len(scans) == 1

    # Cleanup scans older than 365 days (should delete nothing)
    deleted = store.cleanup(days=365)
    assert deleted == 0

    # Verify scan still exists
    scans_after = store.list_scans()
    assert len(scans_after) == 1

    # Cleanup with days=0 would delete everything older than today (which is nothing)
    # but due to how datetime comparison works, might delete today's scans too
    deleted = store.cleanup(days=0)
    # This might be 0 or 1 depending on timing, so we just verify it works
    assert deleted >= 0


def test_scan_record_severity_breakdown() -> None:
    """Test severity breakdown property."""
    from apiposture_pro.features.historical_tracking.models import ScanRecord

    record = ScanRecord(
        critical_count=2,
        high_count=3,
        medium_count=5,
        low_count=1,
        info_count=0,
    )

    breakdown = record.severity_breakdown
    assert "CRITICAL: 2" in breakdown
    assert "HIGH: 3" in breakdown
    assert "MEDIUM: 5" in breakdown
    assert "LOW: 1" in breakdown
    assert "INFO" not in breakdown  # Zero count not included


def test_scan_record_no_findings() -> None:
    """Test severity breakdown with no findings."""
    from apiposture_pro.features.historical_tracking.models import ScanRecord

    record = ScanRecord()
    breakdown = record.severity_breakdown
    assert breakdown == "No findings"


def test_save_scan_with_git_info(temp_dir: Path) -> None:
    """Test saving scan with git information."""
    db_path = temp_dir / "test.db"
    store = HistoryStore(db_path=db_path)

    # Note: This will try to get git info from temp_dir which won't be a git repo
    # So git info will be empty, but that's expected behavior
    result = ScanResult(
        scan_path=temp_dir,
        endpoints=[],
        findings=[],
    )

    scan_id = store.save_scan(result)
    scan = store.get_scan(scan_id)

    assert scan is not None
    # Git info will be None since temp_dir is not a git repo
    assert scan.git_commit is None
    assert scan.git_branch is None
    assert not scan.git_is_dirty
