"""Unit tests for scripts/kb_claim_source_contract_preview.py."""

from __future__ import annotations

import sys
from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "scripts"))

import kb_claim_source_contract_preview as preview  # noqa: E402


def _proposal():
    return {
        "id": "14fa5ecc-ac7a-41c1-807d-a2e85b936617",
        "proposal_type": "attach_evidence",
        "status": "approved",
        "reviewed_by_handle": "m3ta",
        "review_note": "approved with caveats",
        "source_ref": "telegram:m3ta:2026-07-05",
        "payload": {
            "old_claim": {"id": "d0000000-0000-0000-0000-000000000005"},
            "claim_candidates": [
                {
                    "claim_key": "capital_allocation_is_civilizational_steering",
                    "headline": "Capital allocation is a form of civilizational steering.",
                    "body": "Capital allocation chooses which futures get resources.",
                    "type": "structural",
                    "confidence": 0.65,
                    "tags": ["capital-allocation"],
                    "review_note": "Keep the caveat.",
                    "evidence": [{"source_key": "m3ta_telegram_approval"}],
                    "edges": [
                        {
                            "edge_type": "supersedes_component_of",
                            "target_claim_id": "d0000000-0000-0000-0000-000000000005",
                        }
                    ],
                },
                {
                    "claim_key": "internet_finance_is_mechanism_not_telos",
                    "headline": "Internet finance is not Teleo's telos.",
                    "body": "Internet finance is a candidate mechanism.",
                    "type": "normative",
                    "confidence": 0.8,
                    "tags": ["telos"],
                },
            ],
            "source_candidates": [
                {
                    "source_key": "m3ta_telegram_approval",
                    "source_type": "dm",
                    "title": "m3ta Telegram approval",
                    "source_quality": "primary operator direction",
                    "usage_limits": "not external evidence",
                    "key_excerpts": ["approved as caveated"],
                }
            ],
            "proposed_concept_map_dependency": {
                "concept_key": "distributed_market_intelligence",
                "headline": "Distributed market intelligence",
            },
        },
    }


def test_preview_names_claim_and_source_rows_needed():
    result = preview.preview_proposal(_proposal())
    assert result["direct_apply_ready"] is False
    assert len(result["claim_candidates"]) == 2
    assert result["claim_candidates"][0]["requires_canonical_id"] is True
    assert result["source_candidates"][0]["requires_deduplication"] is True


def test_preview_flags_schema_and_contract_gaps():
    result = preview.preview_proposal(_proposal())
    gaps = {item["gap"] for item in result["contract_gaps"]}
    assert "current_apply_role_cannot_insert_claims_or_sources" in gaps
    assert "claim_candidates_need_canonical_ids" in gaps
    assert "public_claims_has_no_body_or_review_note_columns" in gaps
    assert "old_claim_supersession_is_many_successors" in gaps
    assert "concept_map_dependency_has_no_first_class_storage" in gaps


def test_edge_and_evidence_fragments_wait_for_canonical_ids():
    result = preview.preview_proposal(_proposal())
    edge = result["edge_fragments"][0]
    assert edge["from_claim_key"] == "capital_allocation_is_civilizational_steering"
    assert edge["to_claim_id"] == "d0000000-0000-0000-0000-000000000005"
    evidence = result["evidence_fragments"][0]
    assert evidence["claim_key"] == "capital_allocation_is_civilizational_steering"
    assert evidence["source_key"] == "m3ta_telegram_approval"
    assert "canonical source_id" in evidence["blocked_until"]


if __name__ == "__main__":
    import traceback

    failures = 0
    for name, fn in sorted(globals().items()):
        if name.startswith("test_") and callable(fn):
            try:
                fn()
                print(f"PASS {name}")
            except Exception:
                failures += 1
                print(f"FAIL {name}")
                traceback.print_exc()
    raise SystemExit(1 if failures else 0)
