"""맞대어 보기가 **실제로 어긋남을 잡는지**. ★유료 0 — 조회를 안 한다.

★제일 위험한 칸은 「Opik 엔 있고 장부엔 없다」다 — **장부 없이 샀다**는 뜻이다.
실제로 「무료 감사 도구」가 15콜을 사고도 「유료 0」이라 보고한 적이 있고,
그때 알아챌 수 있었던 유일한 자리가 Opik 이었다.
"""
from __future__ import annotations

from tools.grounding_audit import cc_reconcile as rc


def _j(*calls):
    return {"lock": {"logical_cap": 5}, "calls": list(calls)}


def _t(ident, tid="t"):
    return {"id": tid, "start": "", "identity": ident, "model": "m",
            "usage": {}}


class TestItMatchesWhenBothAgree:
    def test_a_clean_run_reconciles(self):
        j = _j({"identity": "a", "status": "ok"},
               {"identity": "b", "status": "ok"})
        r = rc.reconcile(j, [_t("a"), _t("b")])
        assert r["in_journal_not_opik"] == [] and r["in_opik_not_journal"] == []
        assert r["duplicate_buys"] == {}


class TestItCatchesEachMismatch:
    def test_buying_without_journaling_is_caught(self):
        """★★장부에 없는 것이 Opik 에 있으면 **장부 없이 산 것**이다."""
        j = _j({"identity": "a", "status": "ok"})
        r = rc.reconcile(j, [_t("a"), _t("몰래산것")])
        assert r["in_opik_not_journal"] == ["몰래산것"]

    def test_journaled_but_never_logged_is_caught(self):
        j = _j({"identity": "a", "status": "ok"},
               {"identity": "b", "status": "ok"})
        r = rc.reconcile(j, [_t("a")])
        assert r["in_journal_not_opik"] == ["b"]

    def test_the_same_identity_bought_twice_is_caught(self):
        j = _j({"identity": "a", "status": "ok"})
        r = rc.reconcile(j, [_t("a", "t1"), _t("a", "t2")])
        assert r["duplicate_buys"] == {"a": 2}

    def test_an_unlabeled_trace_is_counted_not_ignored(self):
        """★열쇠가 없는 trace 를 조용히 버리면 「맞는다」가 거짓이 된다."""
        j = _j({"identity": "a", "status": "ok"})
        r = rc.reconcile(j, [_t("a"), _t("")])
        assert r["unlabeled_traces"] == 1

    def test_an_uncertain_call_still_counts_as_sent(self):
        """★답을 못 받았어도 **나간 것**이다 — 예산과 대조에서 빠지면 안 된다."""
        j = _j({"identity": "a", "status": "uncertain"})
        r = rc.reconcile(j, [_t("a")])
        assert r["journal_sent"] == ["a"] and r["uncertain"] == ["a"]

    def test_a_planned_but_never_sent_call_is_not_counted_as_sent(self):
        j = _j({"identity": "a", "status": "planned"})
        r = rc.reconcile(j, [])
        assert r["journal_sent"] == []


class TestZeroTracesIsNeverASuccess:
    """★★★앞 판은 **장부 5 · Opik 0** 도 「맞는다」로 끝날 수 있었다 (Codex).

    한쪽 차집합만 봤기 때문이다. 그리고 Opik 을 `metadata` 로 걸러서, 실제로는
    **늘 0건**이 나왔을 것이다 — 실측상 trace 에 남는 것은 `tags` 뿐이다.
    """

    def test_journal_five_opik_zero_is_a_mismatch(self):
        j = _j(*[{"identity": f"i{n}", "status": "ok"} for n in range(5)])
        r = rc.reconcile(j, [])
        assert len(r["in_journal_not_opik"]) == 5
        assert r["in_opik_not_journal"] == []

    def test_the_verdict_needs_both_difference_sets_empty(self):
        """★`main()` 의 판정식을 그대로 재현한다 — 화면 문구가 아니라 **식**."""
        def verdict(r):
            return (not r["in_opik_not_journal"]
                    and not r["in_journal_not_opik"]
                    and not r["duplicate_buys"] and not r["unlabeled_traces"]
                    and bool(r["journal_sent"]) == bool(r["opik_logged"]))

        j = _j(*[{"identity": f"i{n}", "status": "ok"} for n in range(5)])
        assert not verdict(rc.reconcile(j, []))
        good = [_t(f"i{n}") for n in range(5)]
        assert verdict(rc.reconcile(j, good))


class TestTheRunScopeKeepsOldTracesOut:
    """★★내 `probe` trace 하나 때문에 5↔5 가 맞는데도 「안 맞는다」가 났다.

    다음 판은 옛 5건까지 또 잡는다 — **주행 범위**가 있어야 한다 (Codex).
    """

    def test_the_run_id_changes_with_a_new_journal(self):
        from tools.grounding_audit import cc_runner as rr

        lock = {"pack_version": "x"}
        assert rr.run_id(lock, "nonce-a") != rr.run_id(lock, "nonce-b")

    def test_the_run_id_is_stable_across_a_resume(self):
        """★positive control — 재개하면 **같아야** 이어 간다."""
        from tools.grounding_audit import cc_runner as rr

        lock = {"pack_version": "x"}
        assert rr.run_id(lock, "n") == rr.run_id(lock, "n")

    def test_a_new_lock_gives_a_new_run(self):
        from tools.grounding_audit import cc_runner as rr

        assert rr.run_id({"pack_version": "1"}, "n") \
            != rr.run_id({"pack_version": "2"}, "n")

    def test_the_journal_keeps_one_nonce_across_reopens(self, tmp_path):
        from tools.grounding_audit.cc_runner import Journal

        a = Journal(tmp_path / "j.json").nonce()
        b = Journal(tmp_path / "j.json").nonce()
        assert a == b and len(a) == 12
