"""task-2370 P2 — anu_confirm_bot Flask webhook 검증."""
import json
import sys
import time
from pathlib import Path

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parents[2]))


@pytest.fixture
def isolated_workspace(tmp_path, monkeypatch):
    """격리된 workspace를 사용하여 audit log + processed marker가 tmp에 쌓이도록."""
    monkeypatch.setenv("WORKSPACE_ROOT", str(tmp_path))
    monkeypatch.setenv("ANU_CONFIRM_SECRET", "test_secret")
    monkeypatch.setenv("ANU_CONFIRM_BOT_TOKEN", "")  # dry-run
    monkeypatch.setenv("ANU_CONFIRM_CHAT_ID", "")
    # config 모듈 재로드
    import importlib
    from scripts.anu_confirm_bot import config as cfg  # pyright: ignore[reportMissingImports]
    importlib.reload(cfg)
    from scripts.anu_confirm_bot import main as bot_main  # pyright: ignore[reportMissingImports]
    importlib.reload(bot_main)
    return tmp_path, bot_main


def test_healthz_returns_200(isolated_workspace):
    _, bot_main = isolated_workspace
    client = bot_main.app.test_client()
    resp = client.get("/healthz")
    assert resp.status_code == 200
    body = resp.get_json()
    assert body["status"] == "ok"
    assert "trigger_marker" in body


def test_webhook_signature_verification_failure(isolated_workspace):
    """위조 callback_data → 401."""
    _, bot_main = isolated_workspace
    client = bot_main.app.test_client()
    update = {
        "callback_query": {
            "id": "cb1",
            "data": "a:2370:99:9999999999:wrongsig",
        }
    }
    resp = client.post("/webhook", json=update)
    assert resp.status_code == 401


def test_webhook_expired_callback(isolated_workspace):
    """만료된 callback → 401 expired."""
    _, bot_main = isolated_workspace
    from scripts.anu_confirm_bot.signer import sign_callback  # pyright: ignore[reportMissingImports]
    cb = sign_callback("a", 2370, 99, int(time.time()) - 10, "test_secret")
    client = bot_main.app.test_client()
    update = {"callback_query": {"id": "cb1", "data": cb}}
    resp = client.post("/webhook", json=update)
    assert resp.status_code == 401


def test_webhook_diff_action_returns_url(isolated_workspace):
    """diff action은 PR URL 반환 + processed marker 생성."""
    tmp_path, bot_main = isolated_workspace
    from scripts.anu_confirm_bot.signer import sign_callback  # pyright: ignore[reportMissingImports]
    cb = sign_callback("d", 2370, 99, int(time.time()) + 300, "test_secret")
    client = bot_main.app.test_client()
    update = {"callback_query": {"id": "cb1", "data": cb}}
    resp = client.post("/webhook", json=update)
    assert resp.status_code == 200
    body = resp.get_json()
    assert body["outcome"] == "diff_shown"
    # processed marker 생성 확인
    marker = tmp_path / "memory" / "events" / "anu-confirm" / "processed-2370-99-d"
    assert marker.exists()


def test_webhook_replay_protection(isolated_workspace):
    """동일 callback 재클릭 → 409 already_processed."""
    _, bot_main = isolated_workspace
    from scripts.anu_confirm_bot.signer import sign_callback  # pyright: ignore[reportMissingImports]
    cb = sign_callback("d", 2370, 99, int(time.time()) + 300, "test_secret")
    client = bot_main.app.test_client()
    update = {"callback_query": {"id": "cb1", "data": cb}}
    resp1 = client.post("/webhook", json=update)
    assert resp1.status_code == 200
    resp2 = client.post("/webhook", json=update)
    assert resp2.status_code == 409
    body = resp2.get_json()
    assert body["reason"] == "already_processed"


def test_webhook_approve_calls_gh_pr_merge(isolated_workspace, monkeypatch):
    """Approve → gh pr merge 호출 (subprocess.run mock)."""
    _, bot_main = isolated_workspace
    from scripts.anu_confirm_bot.signer import sign_callback  # pyright: ignore[reportMissingImports]

    class FakeProc:
        returncode = 0
        stdout = "merged"
        stderr = ""

    def fake_run(cmd, *_args, **_kwargs):  # pyright: ignore[reportUnusedVariable]
        del _args, _kwargs
        assert cmd[:3] == ["gh", "pr", "merge"]
        assert cmd[3] == "99"
        return FakeProc()

    monkeypatch.setattr("subprocess.run", fake_run)
    cb = sign_callback("a", 2370, 99, int(time.time()) + 300, "test_secret")
    client = bot_main.app.test_client()
    update = {"callback_query": {"id": "cb1", "data": cb}}
    resp = client.post("/webhook", json=update)
    assert resp.status_code == 200
    body = resp.get_json()
    assert body["outcome"] == "merged"


def test_webhook_audit_log_appended(isolated_workspace):
    """callback 처리 후 audit log JSONL append 확인."""
    tmp_path, bot_main = isolated_workspace
    from scripts.anu_confirm_bot.signer import sign_callback  # pyright: ignore[reportMissingImports]
    cb = sign_callback("d", 2370, 88, int(time.time()) + 300, "test_secret")
    client = bot_main.app.test_client()
    client.post("/webhook", json={"callback_query": {"id": "cb1", "data": cb}})
    audit = tmp_path / "memory" / "audit" / "auto-merge.log"
    assert audit.exists()
    lines = [l for l in audit.read_text().splitlines() if l.strip()]
    assert len(lines) >= 1
    rec = json.loads(lines[-1])
    assert rec["task_id"] == "task-2370"
    assert rec["pr_number"] == 88
    assert rec["merger"] == "anu_confirm_bot"


def test_webhook_no_callback_query_ignored(isolated_workspace):
    """callback_query가 없는 update는 무시 (200 ok)."""
    _, bot_main = isolated_workspace
    client = bot_main.app.test_client()
    resp = client.post("/webhook", json={"message": {"text": "hello"}})
    assert resp.status_code == 200
    body = resp.get_json()
    assert body["ok"] is True
