"""
Integration test: full pipeline flow.

Simulates a complete ADW-style pipeline run with:
  1. State initialization + core_fields filter
  2. Multiple phases, each producing a Verdict
  3. Rejection envelope for blocked actions
  4. State gate at the end
  5. Expertise entry for what was learned
"""
import json
import sys
import os

if hasattr(sys.stdout, "reconfigure"):
    sys.stdout.reconfigure(encoding="utf-8")

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Also add the parent of pipeline to ensure direct imports work
_parent = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _parent not in sys.path:
    sys.path.insert(0, _parent)

from pipeline.confidence_ladder import Verdict, VerdictLevel, VerdictReport
from pipeline.rejection_envelope import RejectionEnvelope, Blocker
from pipeline.state_gate import StateGate, FieldSpec, PipelineState
from pipeline.expertise import append_entry, render_context, purge_domain

errors = 0

# ── Step 1: Pipeline state with core_fields ──
state = PipelineState(
    {"plan_file": "plans/feat-123.md", "branch_name": "feat/instant-polls", "issue_number": 42},
    core_fields=["plan_file", "branch_name", "issue_number", "backend_port", "frontend_port", "worktree_path"],
)
assert state.get("plan_file") == "plans/feat-123.md"
print("✓ Step 1: State init with core_fields")

# ── Step 2: Plan phase verdict ──
report = VerdictReport(pipeline_id="adw-abc12345")
report.add(Verdict(VerdictLevel.VERIFIED, "Plan covers all acceptance criteria", ["AC1 covered", "AC2 covered"], source="plan-review"))
print(f"  Plan verdict: {report.aggregate_label}")
assert report.aggregate == VerdictLevel.VERIFIED

# ── Step 3: Build phase produces artifacts ──
state.update(backend_port=9105, frontend_port=9205, worktree_path="/tmp/worktrees/adw-abc12345")
report.add(Verdict(VerdictLevel.PERFECT, "Build completed, tests pass in worktree", ["exit code 0", "all 14 tests pass"], source="build"))
print(f"  Build verdict: PERFECT")

# ── Step 4: A blocked action (leader tries to write a file) ──
no_write_blocker = Blocker(
    name="no_direct_write",
    match=lambda a: a.get("tool") in ("write_file", "patch", "execute_code"),
    reject=lambda a: RejectionEnvelope.block(
        received=a.get("tool", "unknown"),
        reason="LEADER_MUST_NOT_WRITE_FILES",
        allowed="Use delegate_task with a writer subagent",
        hint="Leaders read, delegate, synthesize. Delegate file writes.",
    ),
)
blocked = no_write_blocker.evaluate({"tool": "write_file", "path": "src/main.py"})
assert blocked is not None, "write_file should be blocked"
print(f"✓ Step 4: Action blocked — {blocked.reason}")
print(f"  Allowed: {blocked.allowed}")

# Verify a non-blocked action passes
allowed_action = no_write_blocker.evaluate({"tool": "read_file", "path": "state.json"})
assert allowed_action is None, "read_file should NOT be blocked"
print("✓ Step 4b: read_file passes through")

# ── Step 5: Security review finds gaps (PARTIAL) ──
report.add(Verdict(VerdictLevel.PARTIAL, "No vulnerabilities found, but no live penetration test was run", ["static analysis clean", "dependency scan clean", "NOTE: no live pen test"], source="security-review"))
print(f"  Security verdict: PARTIAL (important: nothing failed, but gap is documented)")

# ── Step 6: Check aggregate after all phases ──
print(f"  Aggregate: {report.aggregate_label}")
assert report.aggregate == VerdictLevel.PARTIAL, f"Aggregate should be PARTIAL (lowest of VERIFIED+PERFECT+PARTIAL), got {report.aggregate_label}"
assert report.passed == True, "PARTIAL should pass (green but documented gap)"
print("✓ Step 6: Aggregate correctly identifies PARTIAL gate")

# ── Step 7: State completeness gate before ship ──
ship_gate = StateGate(
    FieldSpec("plan_file", required=True, predicate=lambda v: isinstance(v, str) and v.startswith("plans/")),
    FieldSpec("branch_name", required=True),
    FieldSpec("issue_number", required=True, type_hint=int),
    FieldSpec("backend_port", required=True, type_hint=int),
    FieldSpec("frontend_port", required=True, type_hint=int),
    FieldSpec("worktree_path", required=True),
    label="pre-ship",
)
gate_result = ship_gate.validate(state)
assert gate_result.passed, f"Complete state should pass ship gate: {gate_result.summary()}"
print(f"✓ Step 7: Ship gate passed ({gate_result.fields_checked} fields validated)")

# ── Step 8: State gate catches missing fields ──
incomplete = PipelineState(
    {"plan_file": "plans/feat-123.md", "branch_name": "feat/instant-polls"},
    core_fields=state._core_fields,
)
fail_result = ship_gate.validate(incomplete)
assert not fail_result.passed
assert "issue_number" in fail_result.missing
assert "backend_port" in fail_result.missing
print(f"✓ Step 8: Ship gate correctly catches missing: {fail_result.missing}")

# ── Step 9: Store expertise about what was learned ──
append_entry(
    "integration-test",
    domain="pipeline",
    insight="PARTIAL verdict allows documented gaps to pass without blocking — critical for green-but-dead prevention",
    source="cron:pipeline-integration-test",
    verified=True,
)
append_entry(
    "integration-test",
    domain="state-gate",
    insight="Required fields must include worktree_path and ports, not just plan_file and branch_name",
    source="cron:pipeline-integration-test",
)
context = render_context("integration-test")
assert "PARTIAL" in context
assert "worktree_path" in context
print("✓ Step 9: Expertise entries stored and loadable")

# ── Step 10: JSON serialization of final report ──
serialized = report.to_json()
restored = VerdictReport.from_json(serialized)
assert restored.aggregate == report.aggregate
assert len(restored.verdicts) == len(report.verdicts)
print("✓ Step 10: Full VerdictReport JSON round-trip")

# Cleanup test expertise file
purge_domain("integration-test", "pipeline")
purge_domain("integration-test", "state-gate")

print(f"\n✅ Integration test passed ({10 - errors}/10)")

if __name__ == "__main__":
    sys.exit(0 if errors == 0 else 1)
