from types import SimpleNamespace
import subprocess

import pytest

from l4d2host.logs import stream_instance_logs


class DummyProcess:
    def __init__(self, lines: list[str]) -> None:
        self.stdout = SimpleNamespace(readline=self._readline)
        self.stderr = SimpleNamespace(readline=lambda: "", read=lambda: "")
        self._lines = iter(lines)
        self.terminated = False
        self.waited = False

    def _readline(self) -> str:
        return next(self._lines, "")

    def poll(self):
        return None if not self.waited else 0

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

    def wait(self, timeout: int | None = None) -> None:
        del timeout
        self.waited = True


def test_stream_instance_logs_yields_lines(monkeypatch: pytest.MonkeyPatch) -> None:
    proc = DummyProcess(["line1\n", "line2\n", ""])

    def fake_popen(cmd, **kwargs):
        del cmd
        del kwargs
        return proc

    monkeypatch.setattr("l4d2host.service_control.subprocess.Popen", fake_popen)

    lines = list(stream_instance_logs("alpha", lines=10, follow=False))
    assert lines == ["line1", "line2"]
    assert proc.waited is True


def test_stream_instance_logs_uses_journalctl_helper(monkeypatch: pytest.MonkeyPatch) -> None:
    calls: list[list[str]] = []

    def fake_stream_command(cmd):
        calls.append(list(cmd))
        return iter(["line1"])

    monkeypatch.setattr("l4d2host.service_control.stream_command", fake_stream_command)

    assert list(stream_instance_logs("alpha", lines=25, follow=False)) == ["line1"]
    assert calls == [
        [
            "sudo",
            "-n",
            "/usr/local/libexec/left4me/left4me-journalctl",
            "alpha",
            "--lines",
            "25",
            "--no-follow",
        ]
    ]


def test_stream_instance_logs_raises_when_helper_fails(monkeypatch: pytest.MonkeyPatch) -> None:
    class FailedProcess:
        stdout = SimpleNamespace(readline=lambda: "")
        stderr = SimpleNamespace(read=lambda: "sudo denied\n")

        def poll(self):
            return 7

        def wait(self, timeout: int | None = None):
            del timeout
            return 7

    monkeypatch.setattr("l4d2host.service_control.subprocess.Popen", lambda cmd, **kwargs: FailedProcess())

    with pytest.raises(subprocess.CalledProcessError) as excinfo:
        list(stream_instance_logs("alpha", lines=10, follow=False))

    assert excinfo.value.returncode == 7
    assert excinfo.value.stderr == "sudo denied\n"
