"""Fake subprocess.CompletedProcess for tests that mock subprocess.run."""

from __future__ import annotations

import signal
import subprocess


class FakeCompleted:
    """Minimal fake for subprocess.CompletedProcess.

    Only the attributes used by the code under test are provided:
    returncode, stdout, stderr.
    """

    def __init__(self, returncode: int, stdout: str, stderr: str) -> None:
        self.returncode = returncode
        self.stdout = stdout
        self.stderr = stderr


class FakePopen:
    """Minimal fake for subprocess.Popen used by nightly pytest streaming."""

    pid = 4242

    def __init__(self, *, stdout: object | None = None, pid: int = 4242) -> None:
        self.pid = pid
        self._returncode: int | None = None
        self.stdout = stdout
        self.terminate_calls = 0
        self.kill_calls = 0
        self.wait_calls = 0

    def poll(self) -> int | None:
        return self._returncode

    def wait(self, timeout: float | None = None) -> int:
        self.wait_calls += 1
        if self._returncode is None:
            self._returncode = -signal.SIGTERM
        return self._returncode

    def terminate(self) -> None:
        self.terminate_calls += 1
        self._returncode = -signal.SIGTERM

    def kill(self) -> None:
        self.kill_calls += 1
        self._returncode = -signal.SIGKILL


class FakePopenTimeoutOnFirstWait(FakePopen):
    """Fake Popen whose first wait() raises TimeoutExpired, then returns SIGKILL."""

    def wait(self, timeout: float | None = None) -> int:
        self.wait_calls += 1
        if self.wait_calls == 1:
            raise subprocess.TimeoutExpired(cmd=["pytest"], timeout=timeout or 0.01)
        self._returncode = -signal.SIGKILL
        return self._returncode