"""E2E: Node label, cordon/uncordon operations via NodeManager."""

import pytest

from citadel_operator.k3s.node import (
    LABEL_MANAGED_BY,
    LABEL_POLICY_NAME,
    LABEL_TERMINATE_AFTER,
    LABEL_TERMINATE_REASON,
    MANAGED_BY_VALUE,
)

pytestmark = pytest.mark.usefixtures("cluster_reachable")


class TestLabelOperations:
    """Verify label_for_termination and clear_termination_labels against real nodes."""

    def test_label_for_termination_applies_all_labels(self, node_manager, node_name):
        node_manager.label_for_termination(
            node_name, reason="e2e-age-exceeded", policy_name="e2e-test-policy"
        )

        info = node_manager.get_node(node_name)
        assert info.labels[LABEL_TERMINATE_REASON] == "e2e-age-exceeded"
        assert info.labels[LABEL_POLICY_NAME] == "e2e-test-policy"
        assert info.labels[LABEL_MANAGED_BY] == MANAGED_BY_VALUE
        assert LABEL_TERMINATE_AFTER in info.labels

    def test_clear_termination_labels(self, node_manager, node_name):
        # Apply labels first
        node_manager.label_for_termination(
            node_name, reason="e2e-clear-test", policy_name="e2e-clear-policy"
        )
        info = node_manager.get_node(node_name)
        assert info.marked_for_termination

        # Clear them
        node_manager.clear_termination_labels(node_name)
        info = node_manager.get_node(node_name)
        assert not info.marked_for_termination
        assert LABEL_TERMINATE_REASON not in info.labels
        assert LABEL_POLICY_NAME not in info.labels
        assert LABEL_MANAGED_BY not in info.labels
        assert LABEL_TERMINATE_AFTER not in info.labels

    def test_labels_are_idempotent(self, node_manager, node_name):
        node_manager.label_for_termination(
            node_name, reason="reason-1", policy_name="policy-1"
        )
        node_manager.label_for_termination(
            node_name, reason="reason-2", policy_name="policy-2"
        )

        info = node_manager.get_node(node_name)
        # Second write wins
        assert info.labels[LABEL_TERMINATE_REASON] == "reason-2"
        assert info.labels[LABEL_POLICY_NAME] == "policy-2"

    def test_marked_for_termination_reflects_labels(self, node_manager, node_name):
        info = node_manager.get_node(node_name)
        assert not info.marked_for_termination

        node_manager.label_for_termination(
            node_name, reason="e2e-flag-test", policy_name="e2e-flag-policy"
        )
        info = node_manager.get_node(node_name)
        assert info.marked_for_termination
        assert info.terminate_reason == "e2e-flag-test"


class TestCordonOperations:
    """Verify cordon/uncordon against real nodes."""

    def test_cordon_makes_node_unschedulable(self, node_manager, node_name):
        node_manager.cordon(node_name)
        info = node_manager.get_node(node_name)
        assert not info.schedulable

    def test_uncordon_restores_schedulability(self, node_manager, node_name):
        node_manager.cordon(node_name)
        node_manager.uncordon(node_name)
        info = node_manager.get_node(node_name)
        assert info.schedulable

    def test_cordon_is_idempotent(self, node_manager, node_name):
        node_manager.cordon(node_name)
        node_manager.cordon(node_name)  # Should not raise
        info = node_manager.get_node(node_name)
        assert not info.schedulable

    def test_cordon_does_not_evict_existing_pods(self, k8s_clients, node_manager, node_name):
        core = k8s_clients["core"]

        # Count pods on node before cordon
        pods_before = core.list_pod_for_all_namespaces(
            field_selector=f"spec.nodeName={node_name}"
        )
        count_before = len(pods_before.items)

        node_manager.cordon(node_name)

        # Count pods on node after cordon (should be the same)
        pods_after = core.list_pod_for_all_namespaces(
            field_selector=f"spec.nodeName={node_name}"
        )
        count_after = len(pods_after.items)

        assert count_after == count_before, (
            f"Cordon changed pod count from {count_before} to {count_after}"
        )
