from __future__ import annotations

import shlex

from k4s.core.executor import Executor, ExecutorError


def q(s: str) -> str:
    """Shell-quote a string for remote commands."""
    return shlex.quote(s)


def run(
    ex: Executor,
    command: str,
    *,
    sudo: bool = False,
    stdin_data: str | bytes | None = None,
    silent: bool = False,
) -> tuple[int, str, str]:
    """Run a command and return (rc, stdout, stderr).

    Debug-level logging (command, rc, stdout, stderr) is handled by
    ``Executor.execute`` itself, so it covers both direct callers and
    this helper uniformly.

    When *silent* is True the debug hook is temporarily suppressed so
    that internal / housekeeping commands do not clutter ``-vv`` output.
    """
    if silent:
        from k4s.core import executor as _ex_mod

        saved = _ex_mod._debug_hook
        _ex_mod.set_executor_debug_hook(None)
        try:
            return ex.execute(command, use_sudo=sudo, stdin_data=stdin_data)
        finally:
            _ex_mod.set_executor_debug_hook(saved)
    return ex.execute(command, use_sudo=sudo, stdin_data=stdin_data)


def check(
    ex: Executor,
    command: str,
    *,
    sudo: bool = False,
    silent: bool = False,
    error_hint: str | None = None,
    stdin_data: str | bytes | None = None,
) -> tuple[int, str, str]:
    """Run a command and raise on non-zero rc."""
    rc, out, err = run(ex, command, sudo=sudo, stdin_data=stdin_data, silent=silent)
    if rc != 0:
        hint = f"\nHint: {error_hint}" if error_hint else ""
        raise ExecutorError(f"Command failed (rc={rc}): {command}\n{err or out}{hint}")
    return rc, out, err
