from __future__ import annotations

import sys
from pathlib import Path

import pytest
from conftest import make_runtime

from scopewrit.canonical import sha256_value
from scopewrit.errors import GatewayError
from scopewrit.gateway import guarded_subprocess
from scopewrit.models import Effect, ScopeRule
from scopewrit.tooling import GuardedToolAdapter


def test_shell_wrapper_runs_only_the_signed_executable(tmp_path: Path) -> None:
    resolved_executable = Path(sys.executable).resolve()
    executable = resolved_executable.name.lower()
    argv = [str(resolved_executable), "-c", "print('scopewrit-shell-ok')"]
    runtime = make_runtime(
        tmp_path / "runtime",
        rules=(
            ScopeRule(
                rule_id="allow-python-smoke",
                effect=Effect.ALLOW,
                action="shell.exec",
                resource=f"shell://{executable}/run",
                required_attributes={"argv_sha256": sha256_value(argv)},
                max_uses=1,
            ),
        ),
    )
    result = guarded_subprocess(
        runtime.engine,
        attestation=runtime.attestation,
        run_id=runtime.manifest.run_id,
        request_id="shell-python-smoke",
        argv=argv,
    )
    assert result.value.returncode == 0
    assert result.value.stdout.strip() == "scopewrit-shell-ok"


def test_shell_allow_rule_without_exact_argv_is_rejected() -> None:
    with pytest.raises(ValueError, match="argv_sha256"):
        ScopeRule(
            rule_id="unsafe-shell-rule",
            effect=Effect.ALLOW,
            action="shell.exec",
            resource="shell://python/run",
        )


def test_browser_adapter_cannot_be_relabelled_as_cloud(tmp_path: Path) -> None:
    runtime = make_runtime(
        tmp_path / "runtime",
        rules=(
            ScopeRule(
                rule_id="allow-browser-docs",
                effect=Effect.ALLOW,
                action="browser.navigate",
                resource="https://docs.example.com/guide/**",
                max_uses=1,
            ),
        ),
    )
    observed = []
    result = GuardedToolAdapter(runtime.engine, adapter="browser").execute(
        attestation=runtime.attestation,
        run_id=runtime.manifest.run_id,
        request_id="browser-navigation",
        action="browser.navigate",
        resource="https://docs.example.com/guide/start",
        arguments={"new_tab": False},
        operation=lambda arguments: observed.append(arguments) or "navigated",
    )
    assert result.value == "navigated"
    assert observed == [{"new_tab": False}]

    with pytest.raises(GatewayError, match="cannot be executed"):
        GuardedToolAdapter(runtime.engine, adapter="cloud").execute(
            attestation=runtime.attestation,
            run_id=runtime.manifest.run_id,
            request_id="adapter-confusion",
            action="browser.navigate",
            resource="https://docs.example.com/guide/start",
            arguments={},
            operation=lambda _: "must-not-run",
        )
