"""Tests for the node health checker.

Tests the pure evaluation logic with mock NodeInfo objects.
No Kubernetes cluster required.
"""

import pytest
from citadel_operator.k3s.health import HealthChecker, HealthState, NodeCondition
from citadel_operator.k3s.node import NodeInfo
from datetime import datetime, timezone, timedelta


def _make_node(
    name: str = "test-node",
    age_hours: float = 10.0,
    ready: bool = True,
    schedulable: bool = True,
    conditions: dict | None = None,
    labels: dict | None = None,
) -> NodeInfo:
    """Helper to create a NodeInfo for testing."""
    default_conditions = {
        "Ready": "True" if ready else "False",
        "DiskPressure": "False",
        "MemoryPressure": "False",
        "PIDPressure": "False",
    }
    if conditions:
        default_conditions.update(conditions)

    return NodeInfo(
        name=name,
        creation_timestamp=datetime.now(timezone.utc) - timedelta(hours=age_hours),
        age_hours=age_hours,
        ready=ready,
        schedulable=schedulable,
        conditions=default_conditions,
        labels=labels or {},
    )


class TestHealthChecker:
    """Tests for HealthChecker evaluation logic."""

    def test_healthy_young_node(self):
        hc = HealthChecker(max_age_hours=48)
        node = _make_node(age_hours=10)
        report = hc.check(node)

        assert report.state == HealthState.HEALTHY
        assert not report.age_exceeded
        assert not report.needs_termination

    def test_healthy_node_approaching_max_age(self):
        """Node at 80%+ of max age should be WARNING."""
        hc = HealthChecker(max_age_hours=48)
        node = _make_node(age_hours=40)  # 83% of 48
        report = hc.check(node)

        assert report.state == HealthState.WARNING
        assert not report.age_exceeded

    def test_node_exceeds_max_age(self):
        hc = HealthChecker(max_age_hours=48)
        node = _make_node(age_hours=50)
        report = hc.check(node)

        assert report.age_exceeded
        assert report.needs_termination

    def test_disk_pressure_is_warning(self):
        hc = HealthChecker(max_age_hours=48)
        node = _make_node(conditions={"DiskPressure": "True"})
        report = hc.check(node)

        assert report.state == HealthState.WARNING

    def test_multiple_pressures_is_error(self):
        hc = HealthChecker(max_age_hours=48)
        node = _make_node(conditions={
            "DiskPressure": "True",
            "MemoryPressure": "True",
        })
        report = hc.check(node)

        assert report.state == HealthState.ERROR

    def test_not_ready_is_error(self):
        hc = HealthChecker(max_age_hours=48)
        node = _make_node(ready=False)
        report = hc.check(node)

        assert report.state == HealthState.ERROR

    def test_not_ready_and_unschedulable_is_terminal(self):
        hc = HealthChecker(max_age_hours=48)
        node = _make_node(ready=False, schedulable=False)
        report = hc.check(node)

        assert report.state == HealthState.TERMINAL
        assert report.needs_termination

    def test_check_all(self):
        hc = HealthChecker(max_age_hours=48)
        nodes = [
            _make_node(name="healthy", age_hours=10),
            _make_node(name="aged", age_hours=50),
            _make_node(name="sick", ready=False),
        ]
        reports = hc.check_all(nodes)

        assert len(reports) == 3
        assert reports[0].state == HealthState.HEALTHY
        assert reports[1].age_exceeded
        assert reports[2].state == HealthState.ERROR

    def test_custom_max_age(self):
        hc = HealthChecker(max_age_hours=24)
        node = _make_node(age_hours=25)
        report = hc.check(node)

        assert report.age_exceeded
        assert report.max_age_hours == 24

    def test_conditions_reported(self):
        hc = HealthChecker(max_age_hours=48)
        node = _make_node()
        report = hc.check(node)

        condition_types = {c.condition_type for c in report.conditions}
        assert "Ready" in condition_types
        assert "DiskPressure" in condition_types
        assert "MemoryPressure" in condition_types
        assert "PIDPressure" in condition_types

    def test_node_marked_for_termination(self):
        """NodeInfo with termination labels should report it."""
        node = _make_node(labels={"citadel.dev/terminate-reason": "max-age"})
        assert node.marked_for_termination
        assert node.terminate_reason == "max-age"

    def test_node_not_marked(self):
        node = _make_node()
        assert not node.marked_for_termination
        assert node.terminate_reason is None
