"""
test_no_admin_override.py — admin override / bypass 차단 회귀 테스트.

1. enqueue-merge --admin 플래그 → exit code != 0, ADMIN OVERRIDE BLOCKED
2. detect_admin_override_attempt 키워드 검출 + no_admin_override=False → MergeQueueError
"""
from __future__ import annotations

import json
import os
import subprocess
import sys
from pathlib import Path

import pytest

# worktree 루트를 sys.path에 추가
_WORKTREE_ROOT = str(Path(__file__).resolve().parents[2])
if _WORKTREE_ROOT not in sys.path:
    sys.path.insert(0, _WORKTREE_ROOT)


def _make_state(tmp_path: Path, task_id: str) -> None:
    """테스트용 task state json 생성 (checksum 포함)."""
    import hashlib

    state_dir = tmp_path / ".tasks" / "state"
    state_dir.mkdir(parents=True, exist_ok=True)

    state: dict = {
        "task_id": task_id,
        "current_state": "HUMAN_APPROVED",
        "transitions": [],
        "evidence": {
            "git_diff_sha": None,
            "changed_paths": [],
            "branch": None,
            "pr_number": None,
            "pr_state": None,
            "ci_checks": {},
            "guard_sh_result": None,
            "gemini_evidence": None,
            "qc_report": None,
        },
    }

    def _canonical(s: dict) -> str:
        payload = {k: v for k, v in s.items() if k != "_checksum"}
        return json.dumps(payload, ensure_ascii=False, sort_keys=True, separators=(",", ":"))

    checksum = hashlib.sha256(_canonical(state).encode()).hexdigest()
    state["_checksum"] = checksum
    state_path = state_dir / f"{task_id}.json"
    state_path.write_text(json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8")


def test_enqueue_merge_admin_flag_blocked(tmp_path: Path) -> None:
    """scripts/taskctl.py enqueue-merge --admin → exit code != 0 + ADMIN OVERRIDE BLOCKED."""
    task_id = "task-2481"
    _make_state(tmp_path, task_id)

    env = {**os.environ, "WORKSPACE_ROOT": str(tmp_path)}

    taskctl_script = _WORKTREE_ROOT + "/scripts/taskctl.py"

    proc = subprocess.run(
        [sys.executable, taskctl_script, "enqueue-merge", task_id, "--pr", "99", "--admin"],
        capture_output=True,
        text=True,
        env=env,
        timeout=30,
    )

    # 종료코드 != 0 검증
    assert proc.returncode != 0, (
        f"expected non-zero exit for --admin flag, got {proc.returncode}\n"
        f"stdout={proc.stdout}\nstderr={proc.stderr}"
    )

    # stderr에 ADMIN OVERRIDE BLOCKED 메시지 확인
    assert "ADMIN OVERRIDE BLOCKED" in proc.stderr or "ADMIN OVERRIDE BLOCKED" in proc.stdout, (
        f"ADMIN OVERRIDE BLOCKED not in output\nstdout={proc.stdout}\nstderr={proc.stderr}"
    )

    # real admin-override.jsonl은 수정되지 않아야 함 (tmp_path에만 evidence)
    # tmp_path 내 admin-override.jsonl은 생성되지 않아야 함
    tmp_override_log = tmp_path / "memory" / "orchestration-audit" / "admin-override.jsonl"
    if tmp_override_log.exists():
        # 파일이 있더라도 내용이 비어있거나 생성 금지
        lines = tmp_override_log.read_text(encoding="utf-8").strip().splitlines()
        assert len(lines) == 0, (
            f"admin-override.jsonl should not have new entries: {lines}"
        )


def test_enqueue_pr_bypass_keyword_blocked(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """detect_admin_override_attempt 키워드 + no_admin_override=False → MergeQueueError."""
    monkeypatch.setenv("WORKSPACE_ROOT", str(tmp_path))

    monkeypatch.delitem(sys.modules, "utils.merge_queue_client", raising=False)
    monkeypatch.delitem(sys.modules, "utils.bot_pr_author", raising=False)

    import utils.merge_queue_client as mqc  # type: ignore[import-not-found]

    log_path = tmp_path / "memory" / "orchestration-audit" / "merge-queue.jsonl"
    monkeypatch.setattr(mqc, "WORKSPACE", tmp_path)
    monkeypatch.setattr(mqc, "MERGE_QUEUE_LOG", log_path)

    # detect_admin_override_attempt: --force-merge 키워드 검출
    reason1 = mqc.detect_admin_override_attempt(["--force-merge"])
    assert reason1 is not None, "expected non-None reason for --force-merge"
    assert "force-merge" in reason1.lower() or "admin" in reason1.lower(), (
        f"reason should mention keyword: {reason1}"
    )

    # detect_admin_override_attempt: bypass 키워드 검출
    reason2 = mqc.detect_admin_override_attempt(["bypass"])
    assert reason2 is not None, "expected non-None reason for 'bypass'"

    # no_admin_override=False → MergeQueueError raise
    with pytest.raises(mqc.MergeQueueError) as exc_info:
        mqc.enqueue_pr(1, no_admin_override=False, dry_run=True)

    assert "admin override" in str(exc_info.value).lower() or \
           "no_admin_override" in str(exc_info.value), (
        f"expected admin override error, got: {exc_info.value}"
    )
