"""Integration tests for the full static analysis layer."""
from __future__ import annotations

from pathlib import Path
from unittest.mock import AsyncMock, patch

import pytest

from pyguard.layers.static import StaticAnalysisLayer
from pyguard.models import PackageInfo, PackageMetadata, Severity


def _make_package(files: dict[str, str], name: str = "testpkg", version: str = "1.0.0") -> PackageInfo:
    return PackageInfo(
        name=name,
        version=version,
        source_path=Path("."),
        files=files,
        metadata=PackageMetadata(),
    )


@pytest.mark.asyncio
async def test_credential_stealer_detected():
    source = Path(
        "tests/fixtures/malicious/credential_stealer.py"
    ).read_text(encoding="utf-8")
    pkg = _make_package({"stealer.py": source})

    with patch("pyguard.detectors.cve.query_vulnerabilities", new=AsyncMock(return_value=[])):
        with patch("pyguard.detectors.cve.get_default_cache") as mc:
            mc.return_value.get.return_value = None
            mc.return_value.set.return_value = None
            layer = StaticAnalysisLayer()
            findings = await layer.analyze(pkg)

    cats = {f.category for f in findings}
    assert "credential_access" in cats or "exfiltration" in cats


@pytest.mark.asyncio
async def test_obfuscated_payload_detected():
    source = Path(
        "tests/fixtures/malicious/obfuscated_payload.py"
    ).read_text(encoding="utf-8")
    pkg = _make_package({"obf.py": source})

    with patch("pyguard.detectors.cve.query_vulnerabilities", new=AsyncMock(return_value=[])):
        with patch("pyguard.detectors.cve.get_default_cache") as mc:
            mc.return_value.get.return_value = None
            mc.return_value.set.return_value = None
            layer = StaticAnalysisLayer()
            findings = await layer.analyze(pkg)

    assert any(f.category == "obfuscation" for f in findings)


@pytest.mark.asyncio
async def test_clean_code_no_critical_findings():
    source = Path(
        "tests/fixtures/clean/simple_util.py"
    ).read_text(encoding="utf-8")
    pkg = _make_package({"util.py": source})

    with patch("pyguard.detectors.cve.query_vulnerabilities", new=AsyncMock(return_value=[])):
        with patch("pyguard.detectors.cve.get_default_cache") as mc:
            mc.return_value.get.return_value = None
            mc.return_value.set.return_value = None
            layer = StaticAnalysisLayer()
            findings = await layer.analyze(pkg)

    assert not any(f.severity == Severity.CRITICAL for f in findings)


@pytest.mark.asyncio
async def test_typosquat_requets_flagged():
    pkg = _make_package({}, name="requets", version="1.0.0")

    with patch("pyguard.detectors.cve.query_vulnerabilities", new=AsyncMock(return_value=[])):
        with patch("pyguard.detectors.cve.get_default_cache") as mc:
            mc.return_value.get.return_value = None
            mc.return_value.set.return_value = None
            layer = StaticAnalysisLayer()
            findings = await layer.analyze(pkg)

    assert any(f.category == "typosquatting" for f in findings)
    assert any(f.severity in (Severity.CRITICAL, Severity.HIGH) for f in findings)
