from __future__ import annotations

from datetime import datetime, timezone
import subprocess

from govoplan_core.commands import fenced_run
from govoplan_core.core.runtime_coordination import LeaseClaim


class _IgnoringProcess:
    def __init__(self) -> None:
        self.terminated = False
        self.killed = False
        self.wait_count = 0

    def poll(self):
        return None if not self.killed else -9

    def terminate(self) -> None:
        self.terminated = True

    def kill(self) -> None:
        self.killed = True

    def wait(self, *, timeout: float):
        self.wait_count += 1
        if not self.killed:
            raise subprocess.TimeoutExpired("command", timeout)
        return -9


def test_fenced_process_is_killed_when_it_ignores_termination() -> None:
    process = _IgnoringProcess()

    fenced_run._terminate_process(process, timeout_seconds=0.01)

    assert process.terminated is True
    assert process.killed is True
    assert process.wait_count == 2


def test_lease_release_is_best_effort_after_database_loss(monkeypatch) -> None:
    claim = LeaseClaim(
        installation_id="installation-1",
        resource_key="scheduler",
        holder_node_id="scheduler-1",
        holder_incarnation="incarnation-1",
        fencing_token=1,
        expires_at=datetime(2026, 8, 1, 12, 0, tzinfo=timezone.utc),
    )

    monkeypatch.setattr(
        fenced_run,
        "get_database",
        lambda: (_ for _ in ()).throw(RuntimeError("database unavailable")),
    )

    fenced_run._release(claim)
