"""Forbidden Bash pattern static guard regression — task-2643 Track D.

회장 verbatim 7 acceptance (spec §5.1):
1. group 1 BACKGROUND_GH_PR_POLL: run_in_background=True + gh pr view → deny
2. group 2 LOOP_SLEEP_GH_PR_POLL: until/while + sleep + gh pr/run/api → deny
3. group 3 GH_RUN_WATCH_POLL: gh run watch / gh run list → deny
4. group 4 SEMANTIC_CI_GEMINI_WAIT: wait/until/poll intent + gh API → deny
5. group 5 EXPLICIT_FORBIDDEN_ACTION: admin override / BOT_APP_TOKEN / chair_authorization 등 → deny
6. allow 정상 명령 (git status / pytest / 단일 비-background gh pr view)
7. fail-closed: tool_input 잘못된 형식 → deny INVALID_TOOL_INPUT_TYPE
"""

import json
import sys
from pathlib import Path

import pytest

_WT = Path(__file__).resolve().parents[2]
if str(_WT) not in sys.path:
    sys.path.insert(0, str(_WT))

from hooks.pre_tool_use_anu_guard import evaluate_tool_call

FIXTURE_ROOT = _WT / "tests" / "fixtures" / "forbidden_bash_pattern"


def _load(name: str):
    base = FIXTURE_ROOT / name
    evidence = json.loads((base / "evidence.json").read_text(encoding="utf-8"))
    expected = json.loads((base / "expected.json").read_text(encoding="utf-8"))
    return evidence, expected


# Acceptance 1-3: 3 deny fixtures parametrized
@pytest.mark.parametrize(
    "fixture_name",
    [
        "bzaona6au_violation_replay",
        "until_sleep_gh_pr_view_deny",
        "run_in_background_gh_pr_view_deny",
    ],
)
def test_fixture_deny_matches_expected(fixture_name):
    evidence, expected = _load(fixture_name)
    decision = evaluate_tool_call(evidence["tool_call"])
    assert decision["decision"] == expected["decision"], (
        f"[{fixture_name}] decision mismatch: got={decision}"
    )
    assert decision["reason"] == expected["reason"]
    assert decision["allowed_alternative"] == expected["must_include_allowed_alternative"]
    for grp in expected["must_include_match_groups"]:
        assert grp in decision["all_match_groups"], (
            f"[{fixture_name}] missing match_group {grp!r} in {decision['all_match_groups']}"
        )


# Acceptance 4: group 4 SEMANTIC_CI_GEMINI_WAIT
def test_group_4_semantic_wait_for_gemini_deny():
    payload = {
        "tool_name": "Bash",
        "tool_input": {
            "command": "echo waiting for gemini review; gh api repos/x/y/pulls/146/reviews",
            "run_in_background": False,
        },
    }
    decision = evaluate_tool_call(payload)
    assert decision["decision"] == "deny"
    assert "SEMANTIC_CI_GEMINI_WAIT" in decision["all_match_groups"]


# Acceptance 5: group 5 explicit forbidden actions
@pytest.mark.parametrize(
    "command",
    [
        "gh pr merge 141 --admin --merge",
        "BOT_APP_TOKEN=xxx gh api graphql",
        "BOT_GITHUB_TOKEN=yyy curl ...",
        "chair_authorization=APPROVED && gh pr merge",
        "trigger admin override now",
        "echo auto-merge activation enable",
    ],
)
def test_group_5_explicit_forbidden_action_deny(command):
    payload = {"tool_name": "Bash", "tool_input": {"command": command}}
    decision = evaluate_tool_call(payload)
    assert decision["decision"] == "deny", f"command did not deny: {command!r} → {decision}"
    assert "EXPLICIT_FORBIDDEN_ACTION" in decision["all_match_groups"]


# Acceptance 6: allow 정상 명령
@pytest.mark.parametrize(
    "command",
    [
        "git status --short",
        "python -m pytest tests/regression/ -x",
        "ls -la /home/jay/workspace",
        "gh pr view 146 --json title",  # 단일, 비-background, statusCheckRollup 없음
    ],
)
def test_normal_command_allow(command):
    payload = {
        "tool_name": "Bash",
        "tool_input": {"command": command, "run_in_background": False},
    }
    decision = evaluate_tool_call(payload)
    assert decision["decision"] == "allow", f"normal command denied: {command!r} → {decision}"


# Acceptance 6b: non-Bash tool 은 항상 allow
def test_non_bash_tool_allow():
    decision = evaluate_tool_call({"tool_name": "Read", "tool_input": {"file_path": "/tmp/x"}})
    assert decision["decision"] == "allow"
    assert decision["reason"] == "NOT_BASH_TOOL"


# Acceptance 7: fail-closed on invalid tool_input
def test_fail_closed_invalid_tool_input():
    decision = evaluate_tool_call({"tool_name": "Bash", "tool_input": "not-a-dict"})
    assert decision["decision"] == "deny"
    assert decision["reason"] == "INVALID_TOOL_INPUT_TYPE"
    assert decision["allowed_alternative"] == "delegated_watcher_contract"


# 추가: gh run watch (group 3)
def test_group_3_gh_run_watch_deny():
    payload = {"tool_name": "Bash", "tool_input": {"command": "gh run watch 12345"}}
    decision = evaluate_tool_call(payload)
    assert decision["decision"] == "deny"
    assert "GH_RUN_WATCH_POLL" in decision["all_match_groups"]
