"""Offline npm installation and isolated command execution for the CLI contract."""

import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile

ROOT = Path(__file__).resolve().parents[1]


def run(args, env, cwd, **kwargs):
    return subprocess.run(args, env=env, cwd=cwd, text=True, capture_output=True, timeout=90, **kwargs)


def install_package(test):
    scratch = tempfile.TemporaryDirectory(prefix="multiacc-packaged-commands-")
    test.addClassCleanup(scratch.cleanup)
    test.work = Path(scratch.name).resolve()
    test.prefix = test.work / "npm prefix"
    test.home = test.work / "home"
    test.home.mkdir()
    npm = shutil.which("npm")
    cache = subprocess.check_output([npm, "config", "get", "cache"], text=True).strip()
    paths = [str(Path(shutil.which(name)).parent) for name in ("node", "python3", "npm")]
    test.env = {
        "HOME": str(test.home), "PATH": os.pathsep.join(dict.fromkeys(paths + ["/usr/bin", "/bin"])),
        "CI": "1", "NO_UPDATE_NOTIFIER": "1", "PYTHONDONTWRITEBYTECODE": "1",
        "CLAUDE_MULTIACC_KEYCHAIN": "0", "CLAUDE_MULTIACC_NO_SYNC": "1", "CODEX_MULTIACC_NO_SYNC": "1",
        "CLAUDE_ACCOUNTS_ROOT": str(test.home / ".claude-accounts"),
        "CODEX_ACCOUNTS_ROOT": str(test.home / ".codex-accounts"),
        "npm_config_cache": cache, "npm_config_update_notifier": "false",
        "npm_config_prefix": str(test.prefix), "npm_config_offline": "true",
        "npm_config_ignore_scripts": "true",
    }
    packed = run([npm, "pack", "--ignore-scripts", "--pack-destination", str(test.work)],
                 test.env, ROOT)
    if packed.returncode:
        raise RuntimeError(packed.stderr)
    # npm 11 emits a JSON array; npm 12 keys it by package name. Test the artifact
    # itself so npm's presentation format cannot strand an otherwise valid release.
    archives = list(test.work.glob("*.tgz"))
    if len(archives) != 1:
        raise RuntimeError(f"Expected one packed archive, found {len(archives)}")
    archive = archives[0]
    installed = run([npm, "install", "-g", "--prefix", str(test.prefix), "--ignore-scripts", "--offline",
                     "--no-audit", "--no-fund", str(archive)], test.env, test.work)
    if installed.returncode:
        raise RuntimeError("Offline install failed; run npm install --ignore-scripts to warm dependencies.\n"
                           + installed.stderr)
    test.package = test.prefix / "lib/node_modules/claude-multiacc"
    test.env["PATH"] = str(test.prefix / "bin") + os.pathsep + test.env["PATH"]
    guard = test.prefix / "bin/npm"
    guard.write_text('#!/usr/bin/env bash\necho "unexpected npm invocation" >&2\nexit 89\n')
    guard.chmod(0o755)
    for name in ("claude", "codex", "security", "launchctl", "crontab", "ln"):
        guard = test.prefix / "bin" / name
        guard.write_text('#!/usr/bin/env bash\n'
                         'printf "%s\\n" "$0 $*" >> "$HOME/tool-calls"\nexit 1\n')
        guard.chmod(0o755)


def seed_pools(test):
    for provider in ("claude", "codex"):
        pool = Path(test.env[f"{provider.upper()}_ACCOUNTS_ROOT"])
        account = pool / "acct-01"
        account.mkdir(parents=True)
        (pool / "accounts.json").write_text(json.dumps({
            "version": 1, "server": "none", "threshold": 90,
            "accounts": [{"id": "acct-01", "email": f"{provider}@example.test",
                          "home": "mac" if os.uname().sysname == "Darwin" else "server"}],
        }))
        credential = ({"tokens": {"access_token": "fixture", "refresh_token": "fixture"}}
                      if provider == "codex" else {"claudeAiOauth": {
                          "accessToken": "fixture", "refreshToken": "fixture", "expiresAt": 9999999999999}})
        filename = "auth.json" if provider == "codex" else ".credentials.json"
        (account / filename).write_text(json.dumps(credential))
        fake = test.prefix / "bin" / provider
        fake.write_text('#!/usr/bin/env bash\nprintf "OK\\n"\n')
        fake.chmod(0o755)
