"""tmux command helpers for okstra-owned container and rerun sessions.

Worker dispatch does not come through here. Workers land in a cmux surface or,
outside cmux, in a cli-wrapper subprocess — neither owns a tmux pane. What is
left is the two places that use tmux purely as a way to hold a long-lived
background process: the container watcher/tail panes and `cmd-rerun.sh`'s
detached spawn.
"""
from __future__ import annotations

import shlex
import shutil
import subprocess
from typing import Optional, Sequence


# container watcher/tail pane 전용 태그. 이 태그가 붙은 pane 은 세션 종료 후에도
# 생존한다 — watcher/tail 의 "세션 후 생존" 불변식이다. 예전에는 SessionEnd 의
# 태그 스캔이 다른 태그만 본다는 사실이 그 생존을 지탱했지만, 지금은 그 스캔과
# 훅과 스크립트 자체가 없어 pane 을 세션 경계에서 회수하는 주체가 아예 없다. 회수는 `down` / `stop-watcher` 의 스코프 reap 뿐이다.
CONTAINER_TAG_OPTION = "@okstra_container_run"


def _shell_quote(s: str) -> str:
    """POSIX shell 안전 인용. shlex.quote 가 모든 메타문자를 처리한다."""
    return shlex.quote(s)


def build_tmux_command(*, session_name: str, cwd: str, run_seq: int,
                       argv: list, okstra_script: str,
                       extra_env: Optional[dict] = None) -> list:
    """tmux new-session 명령을 list 형태로 반환."""
    env_prefix = f"OKSTRA_RUN_SEQ_OVERRIDE={run_seq}"
    if extra_env:
        for k, v in extra_env.items():
            env_prefix += f" {k}={_shell_quote(str(v))}"
    inner = (f"{env_prefix} {_shell_quote(okstra_script)} "
             + " ".join(_shell_quote(a) for a in argv))
    return ["tmux", "new-session", "-d", "-s", session_name, "-c", cwd, inner]


def tmux_available() -> bool:
    if shutil.which("tmux") is None:
        return False
    try:
        result = run_tmux(["display-message", "-p", "#{version}"], timeout=3)
    except (OSError, subprocess.SubprocessError):
        return False
    return result.returncode == 0


def run_tmux(
    args: Sequence[str], *, timeout: int = 10
) -> subprocess.CompletedProcess[str]:
    return subprocess.run(
        ["tmux", *args],
        capture_output=True,
        text=True,
        timeout=timeout,
        check=False,
    )


def new_detached_session(
    session_name: str, cwd: str, first_cmd: str | None = None
) -> str:
    """detached tmux 세션을 띄우고 첫 pane id 를 반환한다.

    cmd-rerun.sh 의 detached spawn 패턴을 python 으로 옮긴 것
    (`tmux new-session -d -s <name> -c <cwd> [cmd]`). `-P -F #{pane_id}` 로
    생성된 pane id 를 받아 이후 split_container_pane 의 `-t` 대상으로 쓴다.
    first_cmd 미지정 시 기본 셸이 첫 pane 을 점유한다 — `true` 처럼 즉시 끝나는
    명령을 주면 단일-윈도우 세션이 split 전에 무너질 수 있으므로(remain-on-exit
    off), holder pane 은 오래 사는 명령이어야 한다.
    """
    args = ["new-session", "-d", "-s", session_name, "-c", cwd,
            "-P", "-F", "#{pane_id}"]
    if first_cmd:
        args.append(first_cmd)
    result = run_tmux(args)
    if result.returncode != 0:
        raise RuntimeError(result.stderr.strip() or "tmux new-session failed")
    return result.stdout.strip()


def split_container_pane(
    *,
    session_pane: Optional[str],
    cwd: str,
    command: str,
    title: str,
    scope_value: str,
    kind: str,
) -> Optional[str]:
    """container watcher/tail pane 을 split 하고 container 전용 태그만 부착한다.

    reap 가 스캔하는 trace 태그는 절대 부착하지 않는다 — CONTAINER_TAG_OPTION 으로
    직접 set-option 한다. session_pane 가 빈값/None(tmux 미사용 경로)이면 raise
    없이 None 반환(degrade).
    """
    if not session_pane:
        return None
    result = run_tmux(
        ["split-window", "-h", "-P", "-F", "#{pane_id}",
         "-c", cwd, "-t", session_pane, command]
    )
    if result.returncode != 0:
        raise RuntimeError(result.stderr.strip() or "tmux split-window failed")
    pane_id = result.stdout.strip()
    set_pane_title(pane_id, title)
    tag_container_pane(pane_id, scope_value)
    return pane_id


def tag_container_pane(pane_id: str, scope_value: str) -> None:
    """container 전용 태그(CONTAINER_TAG_OPTION)만 부착한다.

    reap 가 스캔하는 trace 태그는 절대 거치지 않는다 — 이 태그가 붙은 pane 은
    세션 종료 후에도 생존하고 `down`/`stop-watcher` 의 스코프 reap 로만
    회수된다. holder pane 도 이 태그로 묶어 회수 대상에 포함한다."""
    run_tmux(["set-option", "-p", "-t", pane_id, CONTAINER_TAG_OPTION, scope_value])


def set_pane_title(pane_id: str, title: str) -> None:
    result = run_tmux(["select-pane", "-t", pane_id, "-T", title])
    if result.returncode != 0:
        raise RuntimeError(result.stderr.strip() or "tmux select-pane failed")


def kill_pane(pane_id: str) -> None:
    try:
        run_tmux(["kill-pane", "-t", pane_id])
    except (OSError, subprocess.SubprocessError):
        return
