"""Tests for cleanup_event_backlog.py — the event-flood backlog cleanup script.

Covers the safety invariant the whole cleanup depends on: only events that are
(a) a noise type, (b) strictly older than the observer's per-node checkpoint,
and (c) past the extra min-age safety buffer are ever deleted. Everything
else — unprocessed events, real signals, foreign/ghost node dirs — survives.
"""
from __future__ import annotations

import json
import sys
import time
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import cleanup_event_backlog as cleanup  # noqa: E402


def _write(node_dir: Path, ts: int, etype: str, svc: str = "svc") -> Path:
    p = node_dir / f"evt-{node_dir.name}-{ts}-{etype}-{svc}.json"
    p.write_text("{}")
    return p


def test_deletes_only_processed_noise_past_buffer(tmp_path):
    events_dir = tmp_path / "events"
    node_dir = events_dir / "piha"
    node_dir.mkdir(parents=True)
    now = int(time.time())
    checkpoint = now - 100

    old_healthy = _write(node_dir, now - 7200, "service_healthy")
    old_node_health = _write(node_dir, now - 7200, "node_health")
    recent_healthy = _write(node_dir, now - 30, "service_healthy", svc="svc2")  # within buffer
    unprocessed = _write(node_dir, now + 50, "service_healthy", svc="svc3")     # after checkpoint
    real_signal = _write(node_dir, now - 999999, "healthcheck_failed")

    checkpoints = {"piha": checkpoint}
    candidates, counts = cleanup.scan(
        {"service_healthy", "node_health"}, 3600, checkpoints, now, events_dir
    )

    assert set(candidates) == {old_healthy, old_node_health}
    for f in (recent_healthy, unprocessed, real_signal):
        assert f.exists()
    assert counts["piha"]["healthcheck_failed"]["delete"] == 0
    assert counts["piha"]["healthcheck_failed"]["keep"] == 1


def test_never_deletes_without_checkpoint_for_node(tmp_path):
    """A node dir with no checkpoint entry (ghost/foreign dir) must be left alone."""
    events_dir = tmp_path / "events"
    node_dir = events_dir / "be17cb6eb0f6"
    node_dir.mkdir(parents=True)
    now = int(time.time())
    _write(node_dir, now - 999999, "service_healthy")

    candidates, counts = cleanup.scan(
        {"service_healthy", "node_health"}, 3600, {}, now, events_dir
    )
    assert candidates == []
    assert counts["be17cb6eb0f6"]["service_healthy"]["keep"] == 1


def test_never_deletes_incidents_or_unknown_types(tmp_path):
    events_dir = tmp_path / "events"
    node_dir = events_dir / "vps"
    node_dir.mkdir(parents=True)
    now = int(time.time())
    checkpoint = now - 100
    ha_event = _write(node_dir, now - 999999, "ha_entity_unavailable_long")
    incident_like = _write(node_dir, now - 999999, "containers_not_running")

    candidates, _counts = cleanup.scan(
        {"service_healthy", "node_health"}, 3600, {"vps": checkpoint}, now, events_dir
    )
    assert candidates == []
    assert ha_event.exists()
    assert incident_like.exists()


def test_apply_actually_deletes_and_dry_run_does_not(tmp_path, capsys, monkeypatch):
    events_dir = tmp_path / "events"
    state_dir = tmp_path / "state"
    node_dir = events_dir / "piha"
    node_dir.mkdir(parents=True)
    state_dir.mkdir(parents=True)
    now = int(time.time())
    checkpoint = now - 100
    old_healthy = _write(node_dir, now - 7200, "service_healthy")
    (state_dir / "observer_checkpoint.json").write_text(
        json.dumps({"node_checkpoints": {"piha": checkpoint}})
    )

    monkeypatch.setattr(cleanup, "EVENTS_DIR", events_dir)
    monkeypatch.setattr(cleanup, "CHECKPOINT_FILE", state_dir / "observer_checkpoint.json")
    monkeypatch.setattr(sys, "argv", ["cleanup_event_backlog.py"])
    cleanup.main()
    assert old_healthy.exists()  # dry run: untouched

    monkeypatch.setattr(sys, "argv", ["cleanup_event_backlog.py", "--apply"])
    cleanup.main()
    assert not old_healthy.exists()  # applied: deleted


def test_type_extraction_matches_node_agent_filename_convention():
    assert cleanup._type_from_name("evt-piha-1784215978-service_healthy-mosquitto.json") == "service_healthy"
    assert cleanup._type_from_name("evt-vps-1784215978-node_health-node.json") == "node_health"
    assert cleanup._type_from_name("evt-piha-1784215978-healthcheck_failed-z2m.json") == "healthcheck_failed"
    assert cleanup._type_from_name("evt-piha-1784215978-ha_entity_unavailable_long-node.json") == \
        "ha_entity_unavailable_long"
