"""
Tests for bin/hermes_cleanup.py — Stale process detection and cleanup.
"""

import unittest
from unittest.mock import patch, MagicMock

import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "bin"))

from hermes_cleanup import (
    get_process_age_hours,
    get_child_pids,
    identify_stale_sessions,
    kill_session,
    generate_report,
)


class TestGetProcessAgeHours(unittest.TestCase):
    @patch("hermes_cleanup.subprocess.run")
    def test_returns_age(self, mock_run):
        mock_run.return_value = MagicMock(returncode=0, stdout="3600\n")
        age = get_process_age_hours(1234)
        self.assertAlmostEqual(age, 1.0, delta=0.01)

    @patch("hermes_cleanup.subprocess.run")
    def test_returns_none_on_error(self, mock_run):
        mock_run.return_value = MagicMock(returncode=1, stdout="")
        age = get_process_age_hours(9999)
        self.assertIsNone(age)


class TestGetChildPids(unittest.TestCase):
    @patch("hermes_cleanup.subprocess.run")
    def test_returns_child_pids(self, mock_run):
        mock_run.return_value = MagicMock(returncode=0, stdout="1001\n1002\n")
        pids = get_child_pids(1234)
        self.assertEqual(pids, [1001, 1002])

    @patch("hermes_cleanup.subprocess.run")
    def test_returns_empty_on_no_children(self, mock_run):
        mock_run.return_value = MagicMock(returncode=1, stdout="")
        pids = get_child_pids(1234)
        self.assertEqual(pids, [])


class TestKillSession(unittest.TestCase):
    def test_dry_run_does_not_kill(self):
        session = {
            "session_key": "test",
            "main_pid": 99999,  # unlikely to exist
            "children": [],
        }
        result = kill_session(session, dry_run=True)
        self.assertTrue(result["dry_run"])
        self.assertIn(99999, result["killed"])

    @patch("hermes_cleanup.os.kill")
    def test_kill_terminates_process(self, mock_kill):
        session = {
            "session_key": "test",
            "main_pid": 1234,
            "children": [1235],
        }
        result = kill_session(session, dry_run=False)
        self.assertFalse(result["dry_run"])
        self.assertEqual(mock_kill.call_count, 2)


class TestGenerateReport(unittest.TestCase):
    def test_empty_report(self):
        report = generate_report([])
        self.assertIn("No stale sessions", report)

    def test_report_with_stale(self):
        stale = [{
            "session_key": "test",
            "main_pid": 1234,
            "age_hours": 48.5,
            "cpu_percent": 0.1,
            "total_rss_kb": 20480,
            "total_rss_mb": 20.0,
            "process_count": 2,
            "command": "python3 -m hermes.cli chat",
            "children": [1235],
        }]
        report = generate_report(stale)
        self.assertIn("48.5h", report)
        self.assertIn("20.0 MB", report)


if __name__ == "__main__":
    unittest.main()
