"""test_llm_runner.py — the single LLM dispatch fn (refactor 2). Loaded by PATH. Does NOT invoke claude;
monkeypatches subprocess.run to assert the exact argv/env/kwargs the dispatch builds."""
import importlib.util, json, os
import pytest

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

def _load(name, path):
    spec = importlib.util.spec_from_file_location(name, path)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod

llm = _load("sg_llm_runner", os.path.join(ROOT, "orchestrator", "llm_runner.py"))

class _Captured:
    def __init__(self): self.args = None; self.kwargs = None; self.calls = []
    def __call__(self, *a, **k):
        self.args, self.kwargs = a, k
        self.calls.append((a, k))
        class R: stdout = "ok"; returncode = 0; stderr = ""
        if a[0][1:2] == ["inspect"]:
            R.stdout = json.dumps([{
                "State": {"Running": True},
                "Mounts": [{"Source": llm._CODEX_CRED_SOURCE,
                            "Destination": llm._CODEX_CRED_DEST, "RW": False}],
            }])
        return R()


def _capture_pool(monkeypatch):
    cap = _Captured()
    monkeypatch.setattr(llm.shutil, "which", lambda *a, **k: "/usr/bin/podman")
    monkeypatch.setattr(llm.subprocess, "run", cap)
    return cap

def test_run_llm_builds_exact_claude_argv_and_passes_prompt(monkeypatch):
    cap = _capture_pool(monkeypatch)
    r = llm.run_llm("PROMPT", model="sonnet", effort="medium")
    argv = cap.args[0]
    assert argv[:3] == ["/usr/bin/podman", "exec", "--interactive"]
    assert llm._POOL_CONTAINER in argv
    assert argv[-7:] == ["claude", "-p", "--model", "sonnet", "--effort", "medium",
                         "--dangerously-skip-permissions"]
    assert argv[0] != "claude"
    assert cap.kwargs["input"] == "PROMPT"
    assert cap.kwargs["timeout"] == 600
    assert cap.kwargs["capture_output"] is True and cap.kwargs["text"] is True
    assert r.stdout == "ok"

def test_run_llm_sets_config_dir_env_only_when_given(monkeypatch):
    cap = _capture_pool(monkeypatch)
    llm.run_llm("P", config_dir="/tmp/sg_cfg")
    assert cap.kwargs["env"]["CLAUDE_CONFIG_DIR"] == "/tmp/sg_cfg"
    cap2 = _capture_pool(monkeypatch)
    llm.run_llm("P")
    assert "CLAUDE_CONFIG_DIR" not in cap2.kwargs["env"]


def test_codex_command_runs_only_beneath_podman_exec(monkeypatch):
    cap = _capture_pool(monkeypatch)
    monkeypatch.setenv("SG_LLM_BACKEND", "codex")
    llm.run_llm("PROMPT", model="sonnet", effort="high", cwd="/sandbox/workspaces/review")
    argv = cap.args[0]
    assert argv[0:3] == ["/usr/bin/podman", "exec", "--interactive"]
    codex_at = len(argv) - 10
    assert argv[codex_at:] == [
        "codex", "exec", "--skip-git-repo-check", "-C", "/sandbox/workspaces/review",
        "-m", "gpt-5.5", "-c", "model_reasoning_effort=high", "PROMPT",
    ]
    assert cap.kwargs["input"] == ""
    assert all(call[0][0][0] == "/usr/bin/podman" for call in cap.calls)


def test_fails_closed_when_podman_is_absent(monkeypatch):
    monkeypatch.setattr(llm.shutil, "which", lambda *a, **k: None)
    monkeypatch.setattr(llm.subprocess, "run",
                        lambda *a, **k: pytest.fail("must not run a host LLM"))
    with pytest.raises(llm.ContainmentError, match="podman is unavailable"):
        llm.run_llm("P")


def test_fails_closed_when_pool_is_absent(monkeypatch):
    monkeypatch.setattr(llm.shutil, "which", lambda *a, **k: "/usr/bin/podman")
    calls = []
    def absent(*a, **k):
        calls.append(a[0])
        class R: stdout = ""; stderr = "missing"; returncode = 125
        return R()
    monkeypatch.setattr(llm.subprocess, "run", absent)
    with pytest.raises(llm.ContainmentError, match="pool.*unavailable"):
        llm.run_llm("P")
    assert calls == [["/usr/bin/podman", "inspect", llm._POOL_CONTAINER]]


def test_reuses_pool_with_isolated_home_per_call(monkeypatch):
    cap = _capture_pool(monkeypatch)
    llm.run_llm("one")
    first = cap.calls[-1][0][0]
    llm.run_llm("two")
    second = cap.calls[-1][0][0]
    assert first[first.index("--env") + 1].startswith("HOME=/sandbox/home/security-gate/")
    assert second[second.index("--env") + 1].startswith("HOME=/sandbox/home/security-gate/")
    assert first[first.index("--env") + 1] != second[second.index("--env") + 1]
    assert first[first.index(llm._POOL_CONTAINER)] == second[second.index(llm._POOL_CONTAINER)]
    assert all(call[0][0][0] == "/usr/bin/podman" for call in cap.calls)
