"""task-2554+2 §5 신규 fixture #3: 동일 PR + 동일 head 2회 호출 시 2번째 DEDUPED 판정.

회장 §명시 (2026-05-12): 동일 (pr, head) trigger 시도가 반복되면 atomic dedupe 로 2번째
호출이 ``RESULT_DEDUPED`` + http_post 정확히 1회만 발생.
"""

from __future__ import annotations

import json
from pathlib import Path

import pytest

from anu_v2.owner_trigger_audit import (
    OwnerTriggerAudit,
    RESULT_DEDUPED,
    RESULT_POSTED,
)
from anu_v2.owner_trigger_only import OwnerTriggerOnly


_HEAD_A = "a" * 40
_HEAD_B = "b" * 40
_HEAD_C = "c" * 40


def _write_decision(tmp_path: Path, *, pr: int = 105, head: str = _HEAD_A,
                    fname: str = "decision.json") -> Path:
    decision = {
        "schema": "anu_v2.owner_trigger_decision.v1",
        "task_id": "task-2554+2-test",
        "pr": pr,
        "current_head": head,
        "queue_head": True,
        "current_head_confirmed": True,
        "gemini_evidence_fresh": False,
        "nudge_count_for_pr_head": 0,
        "allowed_action": "POST_GEMINI_REVIEW_TRIGGER_COMMENT",
        "comment_body": "/gemini review",
        "allowed": True,
    }
    p = tmp_path / fname
    p.write_text(json.dumps(decision), encoding="utf-8")
    return p


def _build_module(tmp_path: Path):
    posts: list[dict] = []
    audit = OwnerTriggerAudit(tmp_path)

    def http_post(method, path, body, headers):
        posts.append({"method": method, "path": path, "body": dict(body)})
        return {"status": 201}

    mod = OwnerTriggerOnly(
        workspace_root=tmp_path,
        http_post=http_post,
        token_provider=lambda: "owner-token",
        audit=audit,
    )
    return mod, posts, audit


def test_same_pr_same_head_second_call_returns_deduped(tmp_path):
    """동일 (pr=105, head=_HEAD_A) 2회 호출 → 2번째 DEDUPED + http_post 1회."""
    decision_path = _write_decision(tmp_path)
    mod, posts, audit = _build_module(tmp_path)
    r1 = mod.trigger_gemini_review(
        decision_path=decision_path, owner="o", repo="r", current_head_actual=_HEAD_A,
    )
    r2 = mod.trigger_gemini_review(
        decision_path=decision_path, owner="o", repo="r", current_head_actual=_HEAD_A,
    )
    assert r1.status == RESULT_POSTED
    assert r2.status == RESULT_DEDUPED
    assert r2.error_code == "DEDUPE"
    # http_post 정확히 1회
    assert len(posts) == 1


def test_same_head_three_calls_only_first_posts(tmp_path):
    """동일 (pr, head) 3회 호출 → 1차 POSTED, 2차/3차 DEDUPED. http_post 1회."""
    decision_path = _write_decision(tmp_path)
    mod, posts, audit = _build_module(tmp_path)
    results = [
        mod.trigger_gemini_review(
            decision_path=decision_path, owner="o", repo="r", current_head_actual=_HEAD_A,
        )
        for _ in range(3)
    ]
    statuses = [r.status for r in results]
    assert statuses == [RESULT_POSTED, RESULT_DEDUPED, RESULT_DEDUPED]
    assert len(posts) == 1


def test_different_head_same_pr_each_post_independently(tmp_path):
    """동일 PR 의 head 가 변경되면 각각 별도 trigger — 2개 모두 POSTED."""
    d_a = _write_decision(tmp_path, head=_HEAD_A, fname="a.json")
    d_b = _write_decision(tmp_path, head=_HEAD_B, fname="b.json")
    mod, posts, _ = _build_module(tmp_path)
    r_a = mod.trigger_gemini_review(
        decision_path=d_a, owner="o", repo="r", current_head_actual=_HEAD_A,
    )
    r_b = mod.trigger_gemini_review(
        decision_path=d_b, owner="o", repo="r", current_head_actual=_HEAD_B,
    )
    assert r_a.status == RESULT_POSTED
    assert r_b.status == RESULT_POSTED
    assert len(posts) == 2


def test_different_pr_same_head_each_post_independently(tmp_path):
    """다른 PR 의 head 가 우연히 같아도 (테스트 시나리오) PR 단위로 독립 — 둘 다 POSTED."""
    d_p1 = _write_decision(tmp_path, pr=104, head=_HEAD_C, fname="p104.json")
    d_p2 = _write_decision(tmp_path, pr=105, head=_HEAD_C, fname="p105.json")
    mod, posts, _ = _build_module(tmp_path)
    r1 = mod.trigger_gemini_review(
        decision_path=d_p1, owner="o", repo="r", current_head_actual=_HEAD_C,
    )
    r2 = mod.trigger_gemini_review(
        decision_path=d_p2, owner="o", repo="r", current_head_actual=_HEAD_C,
    )
    assert r1.status == RESULT_POSTED
    assert r2.status == RESULT_POSTED
    assert len(posts) == 2


def test_deduped_record_logged_in_audit(tmp_path):
    """2번째 (DEDUPED) 호출도 audit 에 기록 (atomic, lock 내부)."""
    decision_path = _write_decision(tmp_path)
    mod, _, audit = _build_module(tmp_path)
    mod.trigger_gemini_review(
        decision_path=decision_path, owner="o", repo="r", current_head_actual=_HEAD_A,
    )
    mod.trigger_gemini_review(
        decision_path=decision_path, owner="o", repo="r", current_head_actual=_HEAD_A,
    )
    rows = list(audit._iter_rows())
    # 1차: PENDING + POSTED, 2차: DEDUPED — 총 3 행
    assert len(rows) == 3
    assert rows[0]["result"] == "PENDING"
    assert rows[1]["result"] == "POSTED"
    assert rows[2]["result"] == "DEDUPED"
    assert rows[2]["error_code"] == "DEDUPE"
