"""Tests for the Hermes guard client."""
from __future__ import annotations

import json
import sys
import os

sys.path.insert(0, os.path.dirname(__file__))
import guard_client


def test_surface_for_shell_tools():
    for tool in ("exec", "shell", "bash", "sh", "command", "run", "zsh"):
        assert guard_client._surface_for(tool) == "exec", f"{tool} should be exec"


def test_surface_for_channel_send():
    for tool in ("telegram_send", "discord_send", "slack_send"):
        assert guard_client._surface_for(tool) == "send", f"{tool} should be send"


def test_surface_for_http():
    for tool in ("web_fetch", "http_request", "api_call"):
        assert guard_client._surface_for(tool) == "egress", f"{tool} should be egress"


def test_surface_for_browser():
    assert guard_client._surface_for("browser_navigate") == "tool"


def test_should_govern_readonly():
    assert not guard_client._should_govern("read")
    assert not guard_client._should_govern("file_read")
    assert not guard_client._should_govern("browser_screenshot")


def test_should_govern_mutating():
    assert guard_client._should_govern("http_request")
    assert guard_client._should_govern("telegram_send")
    assert guard_client._should_govern("shell")
    assert guard_client._should_govern("file_write")


def test_build_govern_body_sends_empty_http():
    """The thin plugin sends empty HTTP fields - guard normalizer handles the rest."""
    payload, nonce = guard_client._build_govern_body(
        "http_request",
        {"url": "https://api.stripe.com/v1/charges", "method": "POST"},
        agent_id="test-agent",
    )
    data = json.loads(payload)
    assert data["contract_version"] == "1"
    assert data["nonce"] == nonce
    assert data["ctx"]["caller"]["source"] == "hermes"
    assert data["action"]["tool"] == "http_request"
    assert data["action"]["args"]["url"] == "https://api.stripe.com/v1/charges"
    http = data["attributes"]["request"]["http"]
    assert http["host"] == ""
    assert http["path"] == ""
    assert http["method"] == ""


def test_build_govern_body_shell():
    payload, _ = guard_client._build_govern_body(
        "shell", {"command": "curl https://evil.com"}
    )
    data = json.loads(payload)
    assert data["ctx"]["surface"] == "exec"
    assert data["action"]["operation"] == "exec"
    assert data["action"]["args"]["cmd"] == "curl https://evil.com"


def test_truncate():
    short = "hello"
    assert guard_client._truncate(short) == short
    long = "x" * 20000
    truncated = guard_client._truncate(long)
    assert len(truncated) < len(long)
    assert truncated.endswith("…[truncated]")


def test_evaluate_disabled():
    config = guard_client.GuardConfig(enabled=False)
    v = guard_client.evaluate("http_request", {"url": "https://evil.com"}, config)
    assert v["verdict"] == "allow"


def test_evaluate_readonly_tool():
    config = guard_client.GuardConfig(enabled=True, socket_path="/tmp/fake.sock", token="tok")
    v = guard_client.evaluate("read", {}, config)
    assert v["verdict"] == "allow"


def test_build_inbound_body():
    payload, nonce = guard_client._build_inbound_body(
        channel="telegram",
        sender="alice",
        message="hello world",
        agent_id="test-agent",
        session_id="sess-1",
    )
    data = json.loads(payload)
    assert data["contract_version"] == "1"
    assert data["nonce"] == nonce
    assert data["ctx"]["surface"] == "inbound"
    assert data["ctx"]["caller"]["source"] == "hermes"
    assert data["ctx"]["caller"]["tool"] == "gateway_dispatch"
    assert data["action"]["tool"] == "gateway_dispatch"
    assert data["action"]["operation"] == "receive"
    assert data["action"]["args"]["channel"] == "telegram"
    assert data["action"]["args"]["sender"] == "alice"
    assert data["action"]["args"]["body"] == "hello world"
    http = data["attributes"]["request"]["http"]
    assert http["host"] == "telegram"
    assert http["path"] == "/inbound"
    assert http["body"] == "hello world"


def test_evaluate_inbound_disabled():
    config = guard_client.GuardConfig(enabled=False)
    v = guard_client.evaluate_inbound("telegram", "alice", "hi", config)
    assert v["verdict"] == "allow"


def test_evaluate_inbound_fail_closed():
    config = guard_client.GuardConfig(
        enabled=True,
        socket_path="/tmp/nonexistent.sock",
        token="tok",
        fail_mode="closed",
        timeout_s=0.1,
    )
    v = guard_client.evaluate_inbound("telegram", "alice", "hi", config)
    assert v["verdict"] == "deny"
    assert v.get("fail_mode") is True
