"""Tests for ServicesService.expose_off()."""

from __future__ import annotations

import pytest

from kuberoku.exceptions import NotExposedError
from kuberoku.factory import KuberokuFactory
from kuberoku.k8s.resources import safe_name
from tests.backends.fake import FakeNotFoundError


class TestUnexposeProcess:
    """Unexpose a process type (web)."""

    def test_unexpose_reverts_to_clusterip(
        self,
        deployed_factory: KuberokuFactory,
    ) -> None:
        deployed_factory.services.expose_on("myapp", "web")
        ep = deployed_factory.services.expose_off("myapp", "web")
        assert ep.service_type == "ClusterIP"
        assert ep.method == "clusterip"

    def test_unexpose_updates_service_type(
        self,
        deployed_factory: KuberokuFactory,
    ) -> None:
        deployed_factory.services.expose_on("myapp", "web")
        deployed_factory.services.expose_off("myapp", "web")
        svc_name = safe_name(deployed_factory.prefix, "myapp", "web")
        svc = deployed_factory.k8s.get_service(deployed_factory.namespace, svc_name)
        assert svc["spec"]["type"] == "ClusterIP"

    def test_unexpose_deletes_external_policy(
        self,
        deployed_factory: KuberokuFactory,
    ) -> None:
        deployed_factory.services.expose_on("myapp", "web")
        deployed_factory.services.expose_off("myapp", "web")
        np_name = safe_name(deployed_factory.prefix, "netpol-external", "myapp-web")
        with pytest.raises(FakeNotFoundError):
            deployed_factory.k8s.get_network_policy(
                deployed_factory.namespace,
                np_name,
            )

    def test_unexpose_not_exposed_raises(
        self,
        deployed_factory: KuberokuFactory,
    ) -> None:
        with pytest.raises(NotExposedError):
            deployed_factory.services.expose_off("myapp", "web")

    def test_unexpose_on_step_callback(
        self,
        deployed_factory: KuberokuFactory,
    ) -> None:
        deployed_factory.services.expose_on("myapp", "web")
        steps: list[str] = []
        deployed_factory.services.expose_off("myapp", "web", on_step=steps.append)
        assert len(steps) >= 2
        assert any("Reverting" in s for s in steps)


class TestUnexposeAnnotationTracking:
    """Annotation-based ownership tracking for external policies."""

    def test_unexpose_preserves_policy_if_other_owners(
        self,
        deployed_factory: KuberokuFactory,
    ) -> None:
        """If domains:add also owns the policy, unexpose removes 'expose'
        but keeps the policy for the 'domains' owner."""
        deployed_factory.services.expose_on("myapp", "web")

        # Simulate domains:add adding itself to the annotation
        np_name = safe_name(
            deployed_factory.prefix,
            "netpol-external",
            "myapp-web",
        )
        np = deployed_factory.k8s.get_network_policy(
            deployed_factory.namespace,
            np_name,
        )
        np["metadata"]["annotations"][f"{deployed_factory.domain}/exposed-by"] = "expose,domains"
        deployed_factory.k8s.update_network_policy(
            deployed_factory.namespace,
            np_name,
            np,
        )

        # Unexpose should keep the policy (domains still owns it)
        deployed_factory.services.expose_off("myapp", "web")

        # Policy should still exist
        np = deployed_factory.k8s.get_network_policy(
            deployed_factory.namespace,
            np_name,
        )
        annotations = np.get("metadata", {}).get("annotations", {})
        assert annotations[f"{deployed_factory.domain}/exposed-by"] == "domains"
