"""Tests for Kubernetes linter."""

from yaml_doctor.analyzers.kubernetes import lint_kubernetes


class TestKubernetesLinter:
    def _deploy(self, **overrides):
        """Create a minimal Deployment doc with overrides."""
        doc = {
            "apiVersion": "apps/v1",
            "kind": "Deployment",
            "metadata": {"name": "test", "namespace": "default", "labels": {"app": "test"}},
            "spec": {
                "replicas": 2,
                "strategy": {"type": "RollingUpdate"},
                "template": {
                    "metadata": {"labels": {"app": "test"}},
                    "spec": {
                        "containers": [{
                            "name": "app",
                            "image": "myapp:1.0",
                            "securityContext": {
                                "runAsNonRoot": True,
                                "readOnlyRootFilesystem": True,
                                "allowPrivilegeEscalation": False,
                                "capabilities": {"drop": ["ALL"]},
                            },
                            "resources": {
                                "limits": {"cpu": "500m", "memory": "256Mi"},
                                "requests": {"cpu": "250m", "memory": "128Mi"},
                            },
                            "livenessProbe": {"httpGet": {"path": "/health", "port": 8080}},
                            "readinessProbe": {"httpGet": {"path": "/ready", "port": 8080}},
                        }],
                    },
                },
            },
        }
        spec = doc["spec"]["template"]["spec"]
        cont = spec["containers"][0]
        for k, v in overrides.items():
            if k.startswith("spec."):
                doc["spec"][k[5:]] = v
            elif k.startswith("meta."):
                doc["metadata"][k[5:]] = v
            elif k.startswith("pod."):
                spec[k[4:]] = v
            elif k.startswith("c."):
                cont[k[2:]] = v
            elif k == "no_namespace":
                del doc["metadata"]["namespace"]
            elif k == "no_labels":
                doc["metadata"]["labels"] = {}
        return doc

    def test_clean_deploy_no_findings(self):
        doc = self._deploy()
        findings = lint_kubernetes([doc])
        # May still have K8S015(PDB), K8S019(anti-affinity) — those are low/info
        critical_high = [f for f in findings if f.rule.severity.value in ("critical", "high")]
        assert len(critical_high) == 0

    def test_k8s001_running_as_root(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"][0]["securityContext"] = {}
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S001" for f in findings)

    def test_k8s002_missing_limits(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"][0]["resources"] = {}
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S002" for f in findings)

    def test_k8s003_missing_requests(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"][0]["resources"] = {"limits": {"cpu": "1"}}
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S003" for f in findings)

    def test_k8s004_privileged(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"][0]["securityContext"]["privileged"] = True
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S004" for f in findings)

    def test_k8s005_latest_tag(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"][0]["image"] = "nginx:latest"
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S005" for f in findings)

    def test_k8s005_no_tag(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"][0]["image"] = "nginx"
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S005" for f in findings)

    def test_k8s006_missing_liveness(self):
        doc = self._deploy()
        del doc["spec"]["template"]["spec"]["containers"][0]["livenessProbe"]
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S006" for f in findings)

    def test_k8s007_missing_readiness(self):
        doc = self._deploy()
        del doc["spec"]["template"]["spec"]["containers"][0]["readinessProbe"]
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S007" for f in findings)

    def test_k8s008_writable_fs(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"][0]["securityContext"]["readOnlyRootFilesystem"] = False
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S008" for f in findings)

    def test_k8s010_missing_namespace(self):
        doc = self._deploy()
        del doc["metadata"]["namespace"]
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S010" for f in findings)

    def test_k8s011_host_network(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["hostNetwork"] = True
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S011" for f in findings)

    def test_k8s012_host_pid(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["hostPID"] = True
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S012" for f in findings)

    def test_k8s013_single_replica(self):
        doc = self._deploy()
        doc["spec"]["replicas"] = 1
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S013" for f in findings)

    def test_k8s016_secrets_in_env(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"][0]["env"] = [
            {"name": "API_SECRET", "value": "mytoken123"}
        ]
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S016" for f in findings)

    def test_k8s017_no_strategy(self):
        doc = self._deploy()
        del doc["spec"]["strategy"]
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S017" for f in findings)

    def test_k8s018_caps_not_dropped(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"][0]["securityContext"]["capabilities"] = {}
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S018" for f in findings)

    def test_pod_kind(self):
        doc = {
            "apiVersion": "v1",
            "kind": "Pod",
            "metadata": {"name": "test-pod"},
            "spec": {
                "containers": [{"name": "app", "image": "nginx:latest"}],
            },
        }
        findings = lint_kubernetes([doc])
        assert any(f.rule.rule_id == "K8S005" for f in findings)

    def test_non_workload_skips_container_checks(self):
        doc = {"apiVersion": "v1", "kind": "Service", "metadata": {"name": "svc"}}
        findings = lint_kubernetes([doc])
        # Should only have namespace/label checks at most
        assert not any(f.rule.rule_id.startswith("K8S00") and f.rule.rule_id not in ("K8S009", "K8S010") for f in findings)

    def test_multiple_containers(self):
        doc = self._deploy()
        doc["spec"]["template"]["spec"]["containers"].append({
            "name": "sidecar",
            "image": "sidecar:latest",
        })
        findings = lint_kubernetes([doc])
        latest_findings = [f for f in findings if f.rule.rule_id == "K8S005"]
        assert len(latest_findings) == 1  # only the sidecar

    def test_empty_docs(self):
        assert lint_kubernetes([]) == []
        assert lint_kubernetes([None]) == []
        assert lint_kubernetes(["not a dict"]) == []
