#!/usr/bin/env python3
"""
E9: Golden Loop KAT Tests

Tests for the end-to-end golden loop:
  NL spec → KRISPER IR → BioPoetica AST → Echo symbolization + Sₑ → Centroid regen → Receipt

Claims tested:
  - All sub-receipts present in golden receipt
  - Deterministic: same input → same receipt hash
  - Seed tied to IR: different NL → different regen seed
  - Receipt schema validation

NOT claimed:
  - That this proves all NL specs behave correctly
  - That centroid regen is bit-for-bit identical across backends
  - That this replaces formal verification
"""
import sys
import json
import hashlib
from pathlib import Path

import pytest

# Add paths
HELIX_CDC = Path(__file__).parent.parent
sys.path.insert(0, str(HELIX_CDC))
sys.path.insert(0, str(HELIX_CDC / "tools"))
sys.path.insert(0, str(HELIX_CDC / "gitforest-repo" / "forest" / "krisper"))


# =============================================================================
# Helper
# =============================================================================
def sha256_str(s: str) -> str:
    """SHA256 of string as hex."""
    return hashlib.sha256(s.encode()).hexdigest()


# =============================================================================
# Test: Basic roundtrip - all sub-receipts present
# =============================================================================
def test_golden_loop_basic_roundtrip():
    """
    Claim: Golden loop produces receipt with all four sub-receipts.
    """
    from golden_loop_kat import run_golden_loop

    nl_text = 'compress payload "test" as r1'
    receipt = run_golden_loop(nl_text)

    # Must have all four sub-receipts
    assert "krisper" in receipt, "Missing KRISPER sub-receipt"
    assert "biopoetica" in receipt, "Missing BioPoetica sub-receipt"
    assert "echo" in receipt, "Missing Echo sub-receipt"
    assert "centroid_regen" in receipt, "Missing centroid_regen sub-receipt"

    # Top-level fields
    assert receipt["receipt_type"] == "GOLDEN_LOOP_KAT"
    assert "timestamp" in receipt
    assert "nl_text_sha256" in receipt
    assert "receipt_sha256" in receipt


def test_golden_loop_subreceipts_have_status():
    """
    Claim: Each sub-receipt reports its status.
    """
    from golden_loop_kat import run_golden_loop

    nl_text = 'compress payload "hello" as r1'
    receipt = run_golden_loop(nl_text)

    # Each sub-receipt must have a status
    assert "status" in receipt["krisper"], "KRISPER missing status"
    assert "status" in receipt["biopoetica"], "BioPoetica missing status"
    assert "status" in receipt["echo"], "Echo missing status"
    assert "status" in receipt["centroid_regen"], "centroid_regen missing status"


# =============================================================================
# Test: Determinism - same input → same receipt hash
# =============================================================================
def test_golden_loop_deterministic():
    """
    Claim: Same NL input produces same receipt_sha256 (excluding timestamp).

    Note: We test the deterministic parts by comparing computed sub-values,
    not the full receipt hash (which includes timestamp).
    """
    from golden_loop_kat import run_golden_loop

    nl_text = 'compress payload "determinism test" as r1'

    # Run twice
    r1 = run_golden_loop(nl_text)
    r2 = run_golden_loop(nl_text)

    # Input hash must match
    assert r1["nl_text_sha256"] == r2["nl_text_sha256"], "Input hash differs"

    # KRISPER IR hash must match (if both succeeded)
    if r1["krisper"]["status"] == "success" and r2["krisper"]["status"] == "success":
        assert r1["krisper"]["ir_sha256"] == r2["krisper"]["ir_sha256"], "KRISPER IR hash differs"

    # BioPoetica AST hash must match
    if r1["biopoetica"]["status"] == "success" and r2["biopoetica"]["status"] == "success":
        assert r1["biopoetica"]["ast_sha256"] == r2["biopoetica"]["ast_sha256"], "BioPoetica AST hash differs"

    # Echo symbols hash must match
    if r1["echo"]["status"] == "success" and r2["echo"]["status"] == "success":
        assert r1["echo"]["symbols_sha256"] == r2["echo"]["symbols_sha256"], "Echo symbols hash differs"
        assert r1["echo"]["S_e"] == r2["echo"]["S_e"], "S_e differs"

    # Centroid regen weights hash must match
    if r1["centroid_regen"]["status"] == "success" and r2["centroid_regen"]["status"] == "success":
        assert r1["centroid_regen"]["weights_sha256"] == r2["centroid_regen"]["weights_sha256"], "Weights hash differs"


# =============================================================================
# Test: Seed tied to IR - different NL → different regen seed
# =============================================================================
def test_golden_loop_seed_tied_to_ir():
    """
    Claim: Different NL text produces different regen seed (via IR hash).
    """
    from golden_loop_kat import run_golden_loop

    # Two different NL texts
    r1 = run_golden_loop('compress payload "alpha" as r1')
    r2 = run_golden_loop('compress payload "beta" as r1')

    # Input hashes must differ
    assert r1["nl_text_sha256"] != r2["nl_text_sha256"], "Different inputs should have different hashes"

    # If both KRISPER succeeded, IR hashes should differ
    if r1["krisper"]["status"] == "success" and r2["krisper"]["status"] == "success":
        # The IR hash should differ because the payload differs
        if r1["krisper"]["ir_sha256"] != "N/A" and r2["krisper"]["ir_sha256"] != "N/A":
            assert r1["krisper"]["ir_sha256"] != r2["krisper"]["ir_sha256"], "Different NL should produce different IR"


def test_golden_loop_different_nl_different_symbols():
    """
    Claim: Different NL text produces different Echo symbols.
    """
    from golden_loop_kat import run_golden_loop

    r1 = run_golden_loop('compress payload "foo" as r1')
    r2 = run_golden_loop('recall pattern "bar"')

    # If both Echo succeeded, symbols should differ
    if r1["echo"]["status"] == "success" and r2["echo"]["status"] == "success":
        assert r1["echo"]["symbols_sha256"] != r2["echo"]["symbols_sha256"], "Different NL should produce different symbols"


# =============================================================================
# Test: Receipt schema validation
# =============================================================================
def test_golden_loop_receipt_schema():
    """
    Claim: Receipt has all required schema fields.
    """
    from golden_loop_kat import run_golden_loop

    receipt = run_golden_loop('compress payload "schema test" as r1')

    # Required top-level fields
    required_fields = [
        "receipt_type",
        "timestamp",
        "git_commit",
        "nl_text",
        "nl_text_sha256",
        "krisper",
        "biopoetica",
        "echo",
        "centroid_regen",
        "environment",
        "receipt_sha256",
    ]

    for field in required_fields:
        assert field in receipt, f"Missing required field: {field}"

    # Environment must have required fields
    env_required = ["hostname", "platform", "python_version"]
    for field in env_required:
        assert field in receipt["environment"], f"Missing environment field: {field}"


def test_golden_loop_receipt_type_markers():
    """
    Claim: Each sub-receipt has correct receipt_type marker.
    """
    from golden_loop_kat import run_golden_loop

    receipt = run_golden_loop('compress payload "marker test" as r1')

    # Check receipt_type markers
    assert receipt["krisper"]["receipt_type"] == "KRISPER_COMPILE_SUBRECEIPT"
    assert receipt["biopoetica"]["receipt_type"] == "BIOPOETICA_PARSE_SUBRECEIPT"
    assert receipt["echo"]["receipt_type"] == "ECHO_SYMBOLIZATION_SUBRECEIPT"
    assert receipt["centroid_regen"]["receipt_type"] == "CENTROID_REGEN_SUBRECEIPT"


# =============================================================================
# Test: KRISPER sub-receipt validation
# =============================================================================
def test_golden_loop_krisper_fields():
    """
    Claim: KRISPER sub-receipt has expected fields when successful.
    """
    from golden_loop_kat import run_golden_loop

    receipt = run_golden_loop('compress payload "krisper test" as r1')
    krisper = receipt["krisper"]

    if krisper["status"] == "success":
        assert "text" in krisper, "Missing text field"
        assert "text_sha256" in krisper, "Missing text_sha256"
        assert "ir_sha256" in krisper, "Missing ir_sha256"
        assert "n_operations" in krisper, "Missing n_operations"


# =============================================================================
# Test: BioPoetica sub-receipt validation
# =============================================================================
def test_golden_loop_biopoetica_fields():
    """
    Claim: BioPoetica sub-receipt has expected fields when successful.
    """
    from golden_loop_kat import run_golden_loop

    receipt = run_golden_loop('compress payload "biopoetica test" as r1')
    biopoetica = receipt["biopoetica"]

    if biopoetica["status"] == "success":
        assert "program_name" in biopoetica, "Missing program_name"
        assert "node_count" in biopoetica, "Missing node_count"
        assert "type_counts" in biopoetica, "Missing type_counts"
        assert "ast_sha256" in biopoetica, "Missing ast_sha256"


# =============================================================================
# Test: Echo sub-receipt validation
# =============================================================================
def test_golden_loop_echo_fields():
    """
    Claim: Echo sub-receipt has expected fields when successful.
    """
    from golden_loop_kat import run_golden_loop

    receipt = run_golden_loop('compress payload "echo test" as r1')
    echo = receipt["echo"]

    if echo["status"] == "success":
        assert "symbols_count" in echo, "Missing symbols_count"
        assert "symbols_sha256" in echo, "Missing symbols_sha256"
        assert "S_e" in echo, "Missing S_e"
        assert "plan_id" in echo, "Missing plan_id"
        assert "routing" in echo, "Missing routing"


# =============================================================================
# Test: Centroid regen sub-receipt validation
# =============================================================================
def test_golden_loop_centroid_regen_fields():
    """
    Claim: Centroid regen sub-receipt has expected fields when successful.
    """
    from golden_loop_kat import run_golden_loop

    receipt = run_golden_loop('compress payload "regen test" as r1')
    regen = receipt["centroid_regen"]

    # Status is always present
    assert "status" in regen

    # If successful, check for weight fields
    if regen["status"] == "success":
        assert "seed_hex" in regen, "Missing seed_hex"
        assert "tensor_spec" in regen, "Missing tensor_spec"
        assert "weights_shape" in regen, "Missing weights_shape"
        assert "weights_sha256" in regen, "Missing weights_sha256"

    # If skipped (no atlas), should have reason
    if regen["status"] == "skipped":
        assert "reason" in regen, "Skipped status should have reason"


# =============================================================================
# Test: Empty input handling
# =============================================================================
def test_golden_loop_nonempty_input_required():
    """
    Claim: Golden loop handles various input lengths.
    """
    from golden_loop_kat import run_golden_loop

    # Short but valid input
    receipt = run_golden_loop("test")
    assert "receipt_sha256" in receipt, "Should produce receipt for short input"


# =============================================================================
# Test: Receipt hash is valid
# =============================================================================
def test_golden_loop_receipt_hash_format():
    """
    Claim: Receipt hash is valid hex string.
    """
    from golden_loop_kat import run_golden_loop

    receipt = run_golden_loop('compress payload "hash test" as r1')

    # Receipt hash should be 16-char hex (truncated SHA256)
    receipt_hash = receipt["receipt_sha256"]
    assert len(receipt_hash) == 16, f"Expected 16-char hash, got {len(receipt_hash)}"
    assert all(c in "0123456789abcdef" for c in receipt_hash), "Receipt hash should be hex"


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
