# -*- coding: utf-8 -*-
"""
AR-74 FOCAL TEST SUITE FOR CircuitTracer (app/remediation/self_repair/circuit.py)
Tests:
1. Direct failure at executor marks executor=FAIL, first_proven_break='executor',
   and all downstream nodes (effector, filesystem_runtime_browser, verification,
   final_mission_state) as CircuitStatus.NOT_REACHED with trace_complete=True.
2. FALSE_SUCCESS contradiction detection when verification reports PASS on a
   FALSE_SUCCESS incident.
3. Explicit node_status_overrides and persist() artifact generation.
"""
from __future__ import annotations

import json
import os
import shutil
import tempfile
import pytest

from app.remediation.self_repair.circuit import CircuitTracer
from app.remediation.self_repair.schemas import (
    CircuitStatus,
    EvidenceBundle,
    IncidentFailureType,
    IncidentRecord,
)


def test_circuit_tracer_downstream_not_reached_after_first_break():
    """
    Verifies that once a break occurs at 'executor', all subsequent nodes
    along CANONICAL_CIRCUIT_HIGHWAY without explicit override are assigned
    CircuitStatus.NOT_REACHED (never CircuitStatus.UNKNOWN), listed in
    downstream_not_reached, and trace_complete is True.
    """
    tracer = CircuitTracer()
    incident = IncidentRecord(
        incident_id="inc_ar74_focal_001",
        mission_id="mis_ar74_001",
        failure_type=IncidentFailureType.EXCEPTION,
        observed_symptom="RuntimeError: Executor failed during action dispatch",
        source_component="executor",
        initial_evidence={"failure_stage": "executor"},
    )
    evidence = EvidenceBundle(
        incident_id="inc_ar74_focal_001",
        mission_state={
            "status": "FAILED",
            "spec": {"goal": "test"},
            "plan": {"steps": 1},
        },
        action_history=[
            {"step": 1, "component": "planner", "status": "PASS"},
            {"step": 2, "component": "executor", "status": "FAIL", "error": "RuntimeError"},
        ],
    )

    trace = tracer.trace(incident=incident, evidence=evidence)

    assert trace.first_proven_break == "executor"
    node_map = {n.component: n for n in trace.nodes}
    assert node_map["executor"].status == CircuitStatus.FAIL
    for downstream_comp in ("effector", "filesystem_runtime_browser", "verification", "final_mission_state"):
        actual_status = node_map[downstream_comp].status
        assert actual_status == CircuitStatus.NOT_REACHED, (
            f"Expected {CircuitStatus.NOT_REACHED} for downstream node '{downstream_comp}', "
            f"got {actual_status}"
        )
        assert downstream_comp in trace.downstream_not_reached

    assert trace.trace_complete is True


def test_circuit_tracer_false_success_contradiction_and_persist():
    """
    Verifies FALSE_SUCCESS contradiction detection and JSON persistence.
    """
    tracer = CircuitTracer()
    incident = IncidentRecord(
        incident_id="inc_ar74_focal_002",
        mission_id="mis_ar74_002",
        failure_type=IncidentFailureType.FALSE_SUCCESS,
        observed_symptom="Mission claimed success despite missing output",
        source_component="final_mission_state",
        initial_evidence={},
    )
    evidence = EvidenceBundle(
        incident_id="inc_ar74_focal_002",
        mission_state={"spec": True, "plan": True},
        action_history=[
            {"component": "executor", "status": "PASS"},
            {"component": "effector", "status": "PASS"},
            {"component": "filesystem_runtime_browser", "status": "PASS"},
        ],
        verification_results={"passed": True},
    )

    trace = tracer.trace(incident=incident, evidence=evidence)
    assert len(trace.contradictions) == 1
    assert "FALSE_SUCCESS" in trace.contradictions[0]

    tmp_dir = os.path.join(os.getcwd(), "_ar74_trace_persist_tmp")
    os.makedirs(tmp_dir, exist_ok=True)
    try:
        out_path = tracer.persist(trace, tmp_dir)
        assert os.path.isfile(out_path)
        with open(out_path, "r", encoding="utf-8") as f:
            loaded = json.load(f)
        assert loaded["incident_id"] == "inc_ar74_focal_002"
    finally:
        shutil.rmtree(tmp_dir, ignore_errors=True)
