from __future__ import annotations

import shutil
import subprocess
import threading
from typing import Any

from r_bridge.protocol import SENTINEL


def strip_sentinel(line: str) -> str | None:
    """Return JSON body if line is a protocol line, else None."""
    line = line.rstrip("\n")
    if not line.startswith(SENTINEL):
        return None
    return line[len(SENTINEL):]


def get_r_executable(path: str | None = None) -> str:
    """Return the path to Rscript, searching PATH if not specified."""
    if path:
        return path
    found = shutil.which("Rscript")
    if found is None:
        raise FileNotFoundError("Rscript not found on PATH. Install R or set r_executable.")
    return found


def drain_stderr(
    proc: subprocess.Popen,
    buf: list[str],
    on_line: "callable[[str], None] | None" = None,
) -> threading.Thread:
    """Start a daemon thread that continuously reads proc.stderr into buf.

    If *on_line* is provided it is called with each line immediately after
    it is appended to *buf*, enabling real-time verbose output.
    """

    def _drain():
        try:
            for line in proc.stderr:
                text = line if isinstance(line, str) else line.decode("utf-8", errors="replace")
                buf.append(text)
                if on_line is not None:
                    on_line(text)
        except Exception:
            pass

    t = threading.Thread(target=_drain, daemon=True)
    t.start()
    return t
