"""Tests for the scanner module."""


from yaml_doctor.models import FileType, Grade, Severity
from yaml_doctor.scanner import scan_content, scan_directory, scan_file


class TestScanContent:
    def test_valid_yaml(self):
        result = scan_content("---\nname: test\n", "test.yaml")
        assert result.valid_yaml is True
        assert result.documents == 1
        assert result.score > 0

    def test_invalid_yaml(self):
        result = scan_content("key: [invalid", "bad.yaml")
        assert result.valid_yaml is False
        assert result.score == 0
        assert result.grade == Grade.F

    def test_empty_content(self):
        result = scan_content("", "empty.yaml")
        assert result.valid_yaml is True
        assert result.documents == 0
        assert result.score == 100
        assert result.grade == Grade.A_PLUS

    def test_multi_document(self):
        content = "---\nname: doc1\n---\nname: doc2\n"
        result = scan_content(content, "multi.yaml")
        assert result.documents == 2

    def test_kubernetes_detection(self):
        content = "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: test\nspec:\n  template:\n    spec:\n      containers:\n        - name: app\n          image: nginx:1.21\n"
        result = scan_content(content, "deploy.yaml")
        assert result.file_type == FileType.KUBERNETES

    def test_compose_detection(self):
        content = "services:\n  web:\n    image: nginx\nnetworks:\n  default:\n"
        result = scan_content(content, "docker-compose.yml")
        assert result.file_type == FileType.DOCKER_COMPOSE

    def test_github_actions_detection(self):
        content = "on:\n  push:\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n"
        result = scan_content(content, ".github/workflows/ci.yml")
        assert result.file_type == FileType.GITHUB_ACTIONS

    def test_findings_sorted_by_severity(self):
        content = "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: test\nspec:\n  replicas: 1\n  template:\n    spec:\n      containers:\n        - name: app\n          image: nginx:latest\n          securityContext:\n            privileged: true\n"
        result = scan_content(content, "bad.yaml")
        if len(result.findings) >= 2:
            severities = [f.rule.severity for f in result.findings]
            order = {Severity.CRITICAL: 0, Severity.HIGH: 1, Severity.MEDIUM: 2, Severity.LOW: 3, Severity.INFO: 4}
            ordered = [order.get(s, 5) for s in severities]
            assert ordered == sorted(ordered)

    def test_score_deductions(self):
        # All-bad K8s file should score low
        content = "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: test\nspec:\n  replicas: 1\n  template:\n    spec:\n      containers:\n        - name: app\n          image: nginx:latest\n          securityContext:\n            privileged: true\n"
        result = scan_content(content, "very-bad.yaml")
        assert result.score < 50

    def test_grade_assignment(self):
        result = scan_content("---\nname: ok\n", "ok.yaml")
        assert result.grade in (Grade.A_PLUS, Grade.A)

    def test_stdin_default(self):
        result = scan_content("---\nkey: val\n")
        assert result.file_path == "<stdin>"


class TestScanFile:
    def test_existing_file(self, tmp_path):
        f = tmp_path / "test.yaml"
        f.write_text("---\nname: test\n")
        result = scan_file(str(f))
        assert result.valid_yaml is True

    def test_missing_file(self):
        result = scan_file("/nonexistent/file.yaml")
        assert result.valid_yaml is False
        assert "not found" in result.parse_error.lower()

    def test_invalid_yaml_file(self, tmp_path):
        f = tmp_path / "bad.yaml"
        f.write_text("key: [broken")
        result = scan_file(str(f))
        assert result.valid_yaml is False
        assert result.grade == Grade.F


class TestScanDirectory:
    def test_empty_dir(self, tmp_path):
        scan = scan_directory(str(tmp_path))
        assert scan.total_files == 0
        assert scan.overall_score == 100

    def test_dir_with_yaml(self, tmp_path):
        (tmp_path / "a.yaml").write_text("---\nname: a\n")
        (tmp_path / "b.yml").write_text("---\nname: b\n")
        scan = scan_directory(str(tmp_path))
        assert scan.total_files == 2
        assert len(scan.files) == 2

    def test_recursive(self, tmp_path):
        sub = tmp_path / "sub"
        sub.mkdir()
        (tmp_path / "root.yaml").write_text("---\nname: root\n")
        (sub / "child.yaml").write_text("---\nname: child\n")
        scan = scan_directory(str(tmp_path), recursive=True)
        assert scan.total_files == 2

    def test_no_recursive(self, tmp_path):
        sub = tmp_path / "sub"
        sub.mkdir()
        (tmp_path / "root.yaml").write_text("---\nname: root\n")
        (sub / "child.yaml").write_text("---\nname: child\n")
        scan = scan_directory(str(tmp_path), recursive=False)
        assert scan.total_files == 1

    def test_skip_git_dir(self, tmp_path):
        git = tmp_path / ".git"
        git.mkdir()
        (git / "config.yml").write_text("---\nkey: val\n")
        (tmp_path / "real.yaml").write_text("---\nkey: val\n")
        scan = scan_directory(str(tmp_path))
        assert scan.total_files == 1

    def test_skip_node_modules(self, tmp_path):
        nm = tmp_path / "node_modules"
        nm.mkdir()
        (nm / "pkg.yaml").write_text("---\nkey: val\n")
        scan = scan_directory(str(tmp_path))
        assert scan.total_files == 0

    def test_nonexistent_dir(self):
        scan = scan_directory("/nonexistent/dir")
        assert scan.total_files == 0

    def test_overall_score(self, tmp_path):
        (tmp_path / "good.yaml").write_text("---\nname: good\n")
        scan = scan_directory(str(tmp_path))
        assert scan.overall_score >= 80
        assert scan.overall_grade in (Grade.A_PLUS, Grade.A, Grade.B)
