"""Offline guards for DGR-027's pinned llama.cpp dependency boundary."""

from __future__ import annotations

import hashlib
import importlib.util
import json
import pathlib
import subprocess
import sys


ROOT = pathlib.Path(__file__).resolve().parents[1]
LLAMA_DIR = ROOT / "packages/node/native/llama"
SCRIPT = ROOT / "scripts/llama_cpp_dependency.py"


def _sha256(path: pathlib.Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


def test_lock_and_patch_manifest_are_self_consistent_and_exact() -> None:
    lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
    commit = (LLAMA_DIR / "UPSTREAM_COMMIT").read_text().strip()
    patches = (LLAMA_DIR / "patches/series").read_text().splitlines()
    sums = {
        name: digest
        for digest, name in (
            line.split(maxsplit=1)
            for line in (LLAMA_DIR / "patches/SHA256SUMS").read_text().splitlines()
            if line and not line.startswith("#")
        )
    }

    assert commit == lock["commit"]
    assert len(commit) == 40
    assert lock["retrieval"]["method"] == "git-clone-detached-commit"
    assert lock["retrieval"]["workspace"] == "build/llama.cpp"
    assert lock["expected_source"]["git_tree"] == lock["commit_tree"]
    assert lock["upstream_license"] == "MIT"
    assert patches == lock["patch_series"]
    assert patches == sorted(patches)
    assert patches
    for patch_name in patches:
        patch = LLAMA_DIR / "patches" / patch_name
        assert sums[patch_name] == _sha256(patch)
        assert "Subject: [PATCH" in patch.read_text()


def test_fetch_refuses_a_workspace_outside_the_ignored_build_root(tmp_path: pathlib.Path) -> None:
    completed = subprocess.run(
        [sys.executable, str(SCRIPT), "fetch", "--workspace", str(tmp_path / "llama.cpp")],
        cwd=ROOT,
        capture_output=True,
        text=True,
    )

    assert completed.returncode == 2
    assert "--workspace must equal" in completed.stderr


def test_workspace_refuses_a_symlinked_build_ancestor(tmp_path: pathlib.Path, monkeypatch) -> None:
    spec = importlib.util.spec_from_file_location("llama_cpp_dependency_symlink", SCRIPT)
    assert spec and spec.loader
    dependency = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(dependency)
    root = tmp_path / "repo"
    outside = tmp_path / "outside"
    root.mkdir()
    outside.mkdir()
    (root / "build").symlink_to(outside, target_is_directory=True)
    monkeypatch.setattr(dependency, "ROOT", root)

    try:
        dependency._workspace_source(
            root / "build/llama.cpp",
            {"retrieval": {"workspace": "build/llama.cpp"}},
        )
    except dependency.DependencyError as error:
        assert "may not traverse a symlink" in str(error)
    else:
        raise AssertionError("symlinked build ancestor must be refused")

    (root / "build").unlink()
    workspace = root / "build/llama.cpp"
    workspace.mkdir(parents=True)
    (workspace / "source").symlink_to(outside, target_is_directory=True)
    try:
        dependency._workspace_source(
            workspace,
            {"retrieval": {"workspace": "build/llama.cpp"}},
        )
    except dependency.DependencyError as error:
        assert "source checkout may not be a symlink" in str(error)
    else:
        raise AssertionError("symlinked source checkout must be refused")


def test_fetch_refuses_a_branch_or_repository_override() -> None:
    completed = subprocess.run(
        [sys.executable, str(SCRIPT), "fetch", "--source-repository", "main"],
        cwd=ROOT,
        capture_output=True,
        text=True,
    )

    assert completed.returncode == 2
    assert "unrecognized arguments" in completed.stderr


def test_fetch_reuses_only_a_verified_cached_tree_offline(
    tmp_path: pathlib.Path, monkeypatch
) -> None:
    spec = importlib.util.spec_from_file_location("llama_cpp_dependency", SCRIPT)
    assert spec and spec.loader
    dependency = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(dependency)

    root = tmp_path / "repo"
    source = root / "build/llama.cpp/source"
    upstream = tmp_path / "upstream"
    upstream.mkdir()
    subprocess.run(["git", "init", "-q", str(upstream)], check=True)
    subprocess.run(["git", "-C", str(upstream), "config", "user.email", "test@example.invalid"], check=True)
    subprocess.run(["git", "-C", str(upstream), "config", "user.name", "test"], check=True)
    (upstream / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.14)\n")
    (upstream / "LICENSE").write_text("MIT\n")
    (upstream / "tool.sh").write_text("#!/bin/sh\nexit 0\n")
    (upstream / "tool.sh").chmod(0o755)
    subprocess.run(["git", "-C", str(upstream), "add", "."], check=True)
    subprocess.run(["git", "-C", str(upstream), "commit", "-qm", "fixture"], check=True)
    commit = subprocess.run(
        ["git", "-C", str(upstream), "rev-parse", "HEAD"], check=True, capture_output=True, text=True
    ).stdout.strip()
    tree = subprocess.run(
        ["git", "-C", str(upstream), "rev-parse", "HEAD^{tree}"], check=True, capture_output=True, text=True
    ).stdout.strip()
    blob = subprocess.run(
        ["git", "-C", str(upstream), "rev-parse", "HEAD:CMakeLists.txt"],
        check=True,
        capture_output=True,
        text=True,
    ).stdout.strip()
    source.parent.mkdir(parents=True)
    subprocess.run(["git", "clone", "-q", str(upstream), str(source)], check=True)

    llama_dir = root / "packages/node/native/llama"
    patch_dir = llama_dir / "patches"
    patch_dir.mkdir(parents=True)
    (llama_dir / "UPSTREAM_COMMIT").write_text(f"{commit}\n")
    (patch_dir / "series").write_text("0001-fixture.patch\n")
    patch = patch_dir / "0001-fixture.patch"
    patch.write_text("fixture patch\n")
    (patch_dir / "SHA256SUMS").write_text(f"{_sha256(patch)}  {patch.name}\n")
    (llama_dir / "UPSTREAM_LOCK.json").write_text(json.dumps({
        "upstream": str(upstream),
        "commit": commit,
        "commit_tree": tree,
        "expected_source": {"git_tree": tree},
        "retrieval": {"method": "git-clone-detached-commit", "workspace": "build/llama.cpp"},
        "patched_tree": tree,
        "patch_series": [patch.name],
        "required_upstream_blobs": {"CMakeLists.txt": blob},
        "patched_paths": [],
        "build": {},
        "upstream_license": "MIT",
    }))
    monkeypatch.setattr(dependency, "ROOT", root)
    monkeypatch.setattr(dependency, "LLAMA_DIR", llama_dir)
    monkeypatch.setattr(dependency, "LOCK_PATH", llama_dir / "UPSTREAM_LOCK.json")
    monkeypatch.setattr(dependency, "PATCH_DIR", patch_dir)

    try:
        dependency.fetch(root / "build/llama.cpp")
    except dependency.DependencyError as error:
        assert "detached HEAD" in str(error)
    else:
        raise AssertionError("attached branch cache must be refused")
    subprocess.run(["git", "-C", str(source), "checkout", "--detach", "-q", commit], check=True)
    assert dependency.fetch(root / "build/llama.cpp") == source

    tracked_path = source / "CMakeLists.txt"
    for flag, clear_flag in (
        ("--assume-unchanged", "--no-assume-unchanged"),
        ("--skip-worktree", "--no-skip-worktree"),
    ):
        subprocess.run(["git", "-C", str(source), "update-index", flag, "CMakeLists.txt"], check=True)
        tracked_path.write_text("injected tracked build input\n")
        try:
            dependency.fetch(root / "build/llama.cpp")
        except dependency.DependencyError as error:
            assert "tracked source content differs" in str(error)
        else:
            raise AssertionError(f"tracked cache injection hidden by {flag} must be refused")
        subprocess.run(["git", "-C", str(source), "update-index", clear_flag, "CMakeLists.txt"], check=True)
        subprocess.run(["git", "-C", str(source), "checkout", "--", "CMakeLists.txt"], check=True)

    executable_path = source / "tool.sh"
    for flag, clear_flag in (
        ("--assume-unchanged", "--no-assume-unchanged"),
        ("--skip-worktree", "--no-skip-worktree"),
    ):
        subprocess.run(["git", "-C", str(source), "update-index", flag, "tool.sh"], check=True)
        executable_path.chmod(0o644)
        try:
            dependency.fetch(root / "build/llama.cpp")
        except dependency.DependencyError as error:
            assert "executable mode differs" in str(error)
        else:
            raise AssertionError(f"tracked mode change hidden by {flag} must be refused")
        subprocess.run(["git", "-C", str(source), "update-index", clear_flag, "tool.sh"], check=True)
        subprocess.run(["git", "-C", str(source), "checkout", "--", "tool.sh"], check=True)

    (source / "untracked.txt").write_text("edited\n")
    try:
        dependency.fetch(root / "build/llama.cpp")
    except dependency.DependencyError as error:
        assert "local edits" in str(error)
    else:
        raise AssertionError("dirty cached source must be refused")
    (source / "untracked.txt").unlink()
    (source / ".git/info/exclude").write_text("injected.cmake\n")
    (source / "injected.cmake").write_text("unmanifested input\n")
    try:
        dependency.fetch(root / "build/llama.cpp")
    except dependency.DependencyError as error:
        assert "unmanifested files" in str(error)
    else:
        raise AssertionError("ignored cached source input must be refused")


def test_dependency_script_reports_the_locked_boundary_without_network() -> None:
    completed = subprocess.run(
        [sys.executable, str(SCRIPT), "inspect"],
        cwd=ROOT,
        check=True,
        capture_output=True,
        text=True,
    )
    report = json.loads(completed.stdout)

    assert report["commit"] == (LLAMA_DIR / "UPSTREAM_COMMIT").read_text().strip()
    assert report["patch_count"] == 2
    assert report["model_downloads"] is False
    assert report["semantic_certification"] is False
    assert "dense" in report["glm_stock_limitations"].lower()


def test_patch_stack_does_not_contain_meshnet_control_plane_code() -> None:
    forbidden = ("tracker", "route session", "grpc", "http", "billing", "wallet")
    patch_text = "\n".join(
        (LLAMA_DIR / "patches" / name).read_text().lower()
        for name in (LLAMA_DIR / "patches/series").read_text().splitlines()
    )
    assert not any(term in patch_text for term in forbidden)
