"""Shared helpers."""

from __future__ import annotations

import os
from pathlib import Path

import psutil
from dotenv import dotenv_values


def pid_alive(pid: int | None) -> bool:
    """Return True if a process with the given pid exists."""
    if pid is None:
        return False
    return psutil.pid_exists(pid)


def kill_process_tree(pid: int, timeout: int = 10) -> None:
    """Send SIGTERM to a process and its children, escalate to SIGKILL after *timeout*."""
    try:
        parent = psutil.Process(pid)
    except psutil.NoSuchProcess:
        return
    children = parent.children(recursive=True)
    # Terminate parent first, then children
    for proc in [parent, *children]:
        try:
            proc.terminate()
        except psutil.NoSuchProcess:
            pass
    _, alive = psutil.wait_procs([parent, *children], timeout=timeout)
    for proc in alive:
        try:
            proc.kill()
        except psutil.NoSuchProcess:
            pass


def load_env_file(env_file: str, cwd: Path) -> dict[str, str]:
    """Load an env file and merge it with the current environment.

    Returns a new dict suitable for passing to ``subprocess.Popen(env=...)``.
    """
    merged = dict(os.environ)
    if not env_file:
        return merged
    env_path = (cwd / env_file).resolve()
    if not env_path.exists():
        return merged
    values = dotenv_values(env_path)
    merged.update({k: v for k, v in values.items() if v is not None})
    return merged
