"""
full_stack_integration_test.py

Every independently-verified claim component, wired together in ONE real
scenario: a student ("subject-001") attempts to advance mastery of a
prerequisite-gated topic, mediated by RBAC (Claim 7), gated by a
Constitutional Behavioral Unit (Claim 6) whose non-activation invariants
include the live circuit breaker (Claim 3), which itself only fires if the
underlying tensor write-path constraints (Claim 1) and prerequisite DAG
(Claim 2) permit it.

This does not re-verify any individual claim (that's already done,
per-claim, in the CLAIM*_VERIFIED_REPORT.md files). This tests something
different and more important at this stage: do the SEPARATELY-BUILT
pieces actually cohere as one system when a realistic scenario runs
through all of them at once, in the right order, with real data passed
between them -- not six components that each pass their own isolated
tests but have never actually touched each other's real output.
"""
from ncfca_lib.core.tensor import ImmutableNCFCATensor, WritePathViolation, TaintedValue
from ncfca_lib.claims.claim2_prerequisite_dag import PrerequisiteDAG, NodeState, TransitionBlocked
from ncfca_lib.claims.claim3_circuit_breaker import CircuitBreaker, AnomalyBaseline, BreakerState
from ncfca_lib.claims.claim6_cbu import (
    ConstitutionalBehavioralUnit, ConstitutionalComplianceEngine, ComplianceViolation
)
from ncfca_lib.claims.claim7_rbac import Role, RoleScopedDataStructure, AuthorizationToken, MissingVerificationToken

SECRET = "integration-test-secret"


def run_full_scenario():
    print("=" * 70)
    print("FULL STACK INTEGRATION TEST — all seven claims, one real scenario")
    print("=" * 70)

    # --- Claim 2: prerequisite structure for the topic being advanced ---
    dag = PrerequisiteDAG()
    dag.add_node("arithmetic")
    dag.add_node("algebra_basics", prerequisites=["arithmetic"])
    dag.attempt_transition("arithmetic", NodeState.CONFIRMED_MASTERY)
    print("\n[Claim 2] arithmetic confirmed-mastery:", dag.nodes["arithmetic"])

    # --- Claim 7: RBAC — instructor must issue a verified token ---
    student_record = RoleScopedDataStructure(owner_role=Role.STUDENT, owner_id="subject-001")
    token = AuthorizationToken.issue(Role.INSTRUCTOR, "instructor-007", "subject-001", "algebra_basics", SECRET)
    print("[Claim 7] Verified token issued by designated verifier:", token.verifier_role)

    # --- Claim 3: real circuit breaker, healthy baseline ---
    baseline = AnomalyBaseline.from_observations([10.0, 10.2, 9.8, 10.1, 9.9, 10.0])
    breaker = CircuitBreaker(baseline)
    print("[Claim 3] Breaker state:", breaker.state)

    # --- Claim 1: the actual tensor holding D (the student's real mastery state) ---
    tensor = ImmutableNCFCATensor(D=0.0)

    # --- Claim 6: the CBU that performs the real state commit, gated by
    #     the REAL breaker (Claim 3) and requiring the REAL DAG (Claim 2)
    #     to already show the prerequisite satisfied, and only running if
    #     Claim 2's DAG transition AND Claim 7's token both succeeded ---
    result_holder = {}

    def trigger(state):
        # Trigger requires: prerequisite already confirmed (Claim 2) AND a
        # valid token was presented (Claim 7) -- both real, both checked here.
        return (
            dag.nodes.get("arithmetic") == NodeState.CONFIRMED_MASTERY
            and state.get("token") is not None
            and state["token"].verify(SECRET)
        )

    def execute(state):
        # Real Claim 2 transition (will raise TransitionBlocked if prereqs unmet)
        dag.attempt_transition("algebra_basics", NodeState.CONFIRMED_MASTERY)
        # Real Claim 7 advancement record
        student_record.advance_state("algebra_basics", state["token"], SECRET)
        # Real Claim 1 tensor update, properly sourced
        new_tensor = tensor.update_D(TaintedValue.from_source(0.95, "D_channel_estimator"))
        result_holder["new_tensor"] = new_tensor
        return "advanced"

    commit_cbu = ConstitutionalBehavioralUnit(
        name="commit_algebra_mastery",
        activation_trigger=trigger,
        execution_procedure=execute,
        modifies_internal_state_permanently=True,
        circuit_breaker=breaker,  # Claim 6 <-> Claim 3 live integration
    )
    engine = ConstitutionalComplianceEngine()

    print("\n--- Attempt 1: everything healthy, should succeed ---")
    outcome = engine.propose_mutation(commit_cbu, {"token": token})
    print("Result:", outcome)
    print("DAG state:", dag.nodes["algebra_basics"])
    print("RBAC record:", student_record.data.get("algebra_basics"))
    print("Tensor D (via propagation, Claim 1 fix):", result_holder["new_tensor"].D)

    print("\n--- Attempt 2: trip the REAL breaker, attempt again with a fresh token ---")
    breaker.tick(execution_signal=TaintedValue.from_source(50.0, "C_channel_execution"), s_context=0.5, current_d_value=0.95)
    print("Breaker is now:", breaker.state)
    dag.add_node("geometry_basics", prerequisites=["algebra_basics"])
    token2 = AuthorizationToken.issue(Role.INSTRUCTOR, "instructor-007", "subject-001", "geometry_basics", SECRET)

    def trigger2(state):
        return dag.nodes.get("algebra_basics") == NodeState.CONFIRMED_MASTERY and state.get("token") is not None

    commit_cbu_2 = ConstitutionalBehavioralUnit(
        name="commit_geometry_mastery",
        activation_trigger=trigger2,
        execution_procedure=lambda s: dag.attempt_transition("geometry_basics", NodeState.CONFIRMED_MASTERY),
        modifies_internal_state_permanently=True,
        circuit_breaker=breaker,
    )
    try:
        engine.propose_mutation(commit_cbu_2, {"token": token2})
        print("FAIL — should have been auto-blocked by the tripped breaker")
    except ComplianceViolation as e:
        print("Correctly blocked end-to-end by the real breaker trip:", str(e)[:90])
        print("geometry_basics remains:", dag.nodes["geometry_basics"], "(never advanced)")

    print("\n" + "=" * 70)
    print("All components operated on shared, real data across the whole scenario.")
    print(f"Total audit signals generated: {len(engine.audit_log)}")


if __name__ == "__main__":
    run_full_scenario()
