"""
APEX Engine (Soul/Ψ) — The Judge (v50.5.23)

Symbol: Ψ (Psi)
Role: SOUL — Judgment, Verdict, Constitutional Law
Pipeline: EUREKA → JUDGE → PROOF

Metabolic Stages: 777 (EUREKA), 888 (JUDGE), 889 (PROOF)
Constitutional Floors: F1 (Amanah), F8 (Tri-Witness), F9 (Anti-Hantu), F10 (Ontology)

Trinity III Integration: Time × Energy × Space
    - Time: Has the system cooled enough? (Phoenix-72)
    - Energy: Is the thermodynamic cost justified?
    - Space: Is the solution within bounds?

Governed Power:
    - CAN: Render verdicts (SEAL/SABAR/VOID), generate proofs, seal to vault
    - CANNOT: Generate content (that's AGI), execute actions (that's ASI)
    - AUTHORITY: FINAL VERDICT — sole SEAL power

NOTE: APEX does NOT generate content; it judges content generated by AGI+ASI.
The 888 Judge (Muhammad Arif bin Fazil) is the external sovereign authority.

DITEMPA BUKAN DIBERI — Forged, Not Given.
"""

from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Tuple
from enum import Enum
import time
import hashlib
import json

from arifos.core.system.trinity import (
    Verdict,
    VerdictEnergy,
    TrinityConstraint,
    ThreeTrinities,
    ThermodynamicSignature
)


# =============================================================================
# VERDICT PROTOCOL
# =============================================================================

@dataclass
class VoidJustification:
    """
    Required for VOID verdict (Anti-Bangang Protocol).

    VOID is EXPENSIVE:
        - Must cite specific floor (F1-F13)
        - Must provide evidence
        - Must pass tri-witness
    """
    floor: str  # F1, F2, ... F13
    reason: str
    evidence: str
    tri_witness_approved: bool = False

    def is_valid(self) -> bool:
        """VOID justification must be complete."""
        return bool(self.floor and self.reason and self.evidence)


@dataclass
class ProofPacket:
    """
    Cryptographic proof of judgment (zkPC-light).

    Contains:
        - Merkle root of judgment chain
        - Hash of inputs (AGI + ASI outputs)
        - Hash of verdict
        - Timestamp
    """
    merkle_root: str
    input_hash: str
    verdict_hash: str
    timestamp: float
    chain: List[str] = field(default_factory=list)

    @staticmethod
    def compute_hash(data: Any) -> str:
        """Compute SHA256 hash of data."""
        if isinstance(data, dict):
            data = json.dumps(data, sort_keys=True)
        return hashlib.sha256(str(data).encode()).hexdigest()[:16]


# =============================================================================
# APEX STAGE RESULTS
# =============================================================================

@dataclass
class EurekaResult:
    """Stage 777: EUREKA moment — Solution synthesis."""
    synthesis: str
    genius_index: float  # G = A × P × X × E²
    components: Dict[str, float]  # A, P, X, E breakdown
    breakthrough: bool
    eureka_hash: str


@dataclass
class JudgeResult:
    """Stage 888: JUDGE — Verdict rendering."""
    verdict: Verdict
    reason: str
    three_trinities: Dict[str, Any]
    floor_checks: Dict[str, bool]
    void_justification: Optional[VoidJustification] = None
    genius_stats: Dict[str, float] = field(default_factory=dict)
    compass_alignment: float = 0.0


@dataclass
class ProofResult:
    """Stage 889: PROOF — Cryptographic seal."""
    proof_packet: ProofPacket
    verified: bool
    seal_ready: bool


@dataclass
class APEXOutput:
    """Complete APEX engine output."""
    status: str  # SEAL, SABAR, VOID
    session_id: str
    verdict: Verdict

    # Stage outputs
    eureka: Optional[EurekaResult] = None
    judge: Optional[JudgeResult] = None
    proof: Optional[ProofResult] = None

    # Three Trinities evaluation
    three_trinities: Optional[ThreeTrinities] = None

    # Thermodynamics
    thermodynamics: Optional[ThermodynamicSignature] = None

    # Floor checks
    floors_checked: List[str] = field(default_factory=list)
    floor_violations: List[str] = field(default_factory=list)

    # Audit trail
    audit_hash: str = ""

    def as_dict(self) -> Dict[str, Any]:
        return {
            "status": self.status,
            "session_id": self.session_id,
            "verdict": self.verdict.value,
            "eureka": {
                "synthesis": self.eureka.synthesis[:200] if self.eureka else "",
                "genius_index": self.eureka.genius_index if self.eureka else 0,
                "breakthrough": self.eureka.breakthrough if self.eureka else False
            },
            "judge": {
                "verdict": self.judge.verdict.value if self.judge else "",
                "reason": self.judge.reason if self.judge else ""
            } if self.judge else None,
            "proof": {
                "merkle_root": self.proof.proof_packet.merkle_root if self.proof else "",
                "verified": self.proof.verified if self.proof else False
            } if self.proof else None,
            "three_trinities": self.three_trinities.as_dict() if self.three_trinities else None,
            "thermodynamics": self.thermodynamics.as_dict() if self.thermodynamics else None,
            "floors_checked": self.floors_checked,
            "floor_violations": self.floor_violations,
            "audit_hash": self.audit_hash
        }


# =============================================================================
# APEX ENGINE
# =============================================================================

class APEXEngine:
    """
    APEX Engine (Soul/Ψ) — The Judge

    Executes: EUREKA → JUDGE → PROOF
    Authority: FINAL VERDICT — sole SEAL power

    Constitutional Mandate:
        - F1: Amanah (Reversibility) — All actions must be auditable
        - F8: Tri-Witness — Human × AI × Earth must approve
        - F9: Anti-Hantu — No deceptive patterns
        - F10: Ontology Lock — Cannot claim consciousness/emotions
    """

    # Floor thresholds
    FLOOR_THRESHOLDS = {
        "F1": {"type": "HARD", "check": "amanah_reversible"},
        "F2": {"type": "HARD", "check": "truth >= 0.99"},
        "F3": {"type": "SOFT", "check": "peace_squared >= 1.0"},
        "F4": {"type": "SOFT", "check": "kappa_r >= 0.7"},
        "F5": {"type": "HARD", "check": "omega_0 in [0.03, 0.05]"},
        "F6": {"type": "HARD", "check": "delta_S <= 0"},
        "F7": {"type": "SOFT", "check": "rasa_active"},
        "F8": {"type": "DERIVED", "check": "tri_witness >= 0.95"},
        "F9": {"type": "SOFT", "check": "anti_hantu <= 0.3"},
        "F10": {"type": "HARD", "check": "ontology_locked"},
        "F11": {"type": "HARD", "check": "command_auth_verified"},
        "F12": {"type": "HARD", "check": "injection_risk < 0.85"},
        "F13": {"type": "HARD", "check": "sovereign_approval"}
    }

    # Genius equation components
    GENIUS_WEIGHTS = {
        "A": 0.30,  # AKAL (Clarity)
        "P": 0.20,  # PRESENT (Peace)
        "X": 0.20,  # EXPLORATION (Trust)
        "E": 0.30   # ENERGY (squared)
    }

    def __init__(self, session_id: Optional[str] = None):
        """Initialize APEX Engine."""
        self.session_id = session_id or f"apex_{int(time.time()*1000)}"
        self.start_time = time.time()
        self._verdict_energy = VerdictEnergy()
        self._judgment_chain: List[str] = []

    # =========================================================================
    # STAGE 777: EUREKA
    # =========================================================================

    def eureka(self, agi_output: Dict[str, Any], asi_output: Dict[str, Any]) -> EurekaResult:
        """
        Stage 777: EUREKA — Solution synthesis.

        Combines AGI reasoning with ASI empathy to form complete solution.
        Calculates Genius Index: G = A × P × X × E²
        """
        # Extract components
        agi_status = agi_output.get("status", "SABAR")
        asi_status = asi_output.get("status", "SABAR")

        # Calculate APEX components
        # A (AKAL/Clarity): From AGI reasoning quality
        think = agi_output.get("think", {})
        A = think.get("confidence", 0.5) if think else 0.5

        # P (PRESENT/Peace): From ASI alignment
        align = asi_output.get("align", {})
        P = align.get("peace_squared", 0.5) if align else 0.5

        # X (EXPLORATION/Trust): From evidence grounding
        evidence = asi_output.get("evidence", {})
        X = evidence.get("truth_grounding", 0.5) if evidence else 0.5

        # E (ENERGY): From thermodynamic efficiency
        E = 0.8  # Default good energy

        # Genius Index: G = A × P × X × E²
        G = A * P * X * (E ** 2)

        # Synthesize solution
        forge = agi_output.get("forge", {})
        synthesis = forge.get("solution_draft", "") if forge else "No solution synthesized"

        # Determine breakthrough
        breakthrough = G > 0.8 and agi_status == "SEAL" and asi_status == "SEAL"

        # Hash for audit
        eureka_hash = ProofPacket.compute_hash({
            "synthesis": synthesis,
            "G": G,
            "components": {"A": A, "P": P, "X": X, "E": E}
        })

        return EurekaResult(
            synthesis=synthesis,
            genius_index=G,
            components={"A": A, "P": P, "X": X, "E": E},
            breakthrough=breakthrough,
            eureka_hash=eureka_hash
        )

    # =========================================================================
    # STAGE 888: JUDGE
    # =========================================================================

    def judge(self, eureka_result: EurekaResult, agi_output: Dict[str, Any],
              asi_output: Dict[str, Any]) -> JudgeResult:
        """
        Stage 888: JUDGE — Render verdict using Three Trinities.

        Anomalous Contrast Protocol:
            - VOID is EXPENSIVE (must justify)
            - SEAL is EARNED (all trinities approve)
            - SABAR is DEFAULT (refine and retry)
        """
        # Build Three Trinities evaluation
        three_trinities = self._build_three_trinities(agi_output, asi_output, eureka_result)

        # Check all floors
        floor_checks = self._check_all_floors(agi_output, asi_output, eureka_result)

        # Collect violations
        hard_violations = []
        soft_violations = []

        for floor, passed in floor_checks.items():
            if not passed:
                floor_type = self.FLOOR_THRESHOLDS.get(floor, {}).get("type", "SOFT")
                if floor_type == "HARD":
                    hard_violations.append(floor)
                else:
                    soft_violations.append(floor)

        # Determine verdict
        void_justification = None

        if hard_violations:
            # Hard floor violation → VOID (but needs justification)
            void_justification = VoidJustification(
                floor=hard_violations[0],
                reason=f"Hard floor {hard_violations[0]} violated",
                evidence=f"Floor check returned False for {hard_violations[0]}",
                tri_witness_approved=True  # System auto-approves hard violations
            )
            verdict = Verdict.VOID
            reason = f"VOID: Hard floor violation ({', '.join(hard_violations)})"

        elif soft_violations:
            # Soft violation → SABAR
            verdict = Verdict.SABAR
            reason = f"SABAR: Soft floors need attention ({', '.join(soft_violations)})"

        elif three_trinities.all_trinities_approve():
            # All clear → SEAL
            verdict = Verdict.SEAL
            reason = "SEAL: All trinities approve, all floors pass"

        else:
            # Default → SABAR
            verdict = Verdict.SABAR
            reason = "SABAR: Trinities not converged, refinement needed"

        # Genius stats
        genius_stats = {
            "G": eureka_result.genius_index,
            **eureka_result.components
        }

        # Compass alignment (ethical direction)
        compass_alignment = three_trinities.governance.tri_witness

        return JudgeResult(
            verdict=verdict,
            reason=reason,
            three_trinities=three_trinities.as_dict(),
            floor_checks=floor_checks,
            void_justification=void_justification,
            genius_stats=genius_stats,
            compass_alignment=compass_alignment
        )

    def _build_three_trinities(self, agi_output: Dict[str, Any], asi_output: Dict[str, Any],
                                eureka: EurekaResult) -> ThreeTrinities:
        """Build Three Trinities evaluation from engine outputs."""
        from arifos.core.system.trinity import TrinityStructural, TrinityGovernance, TrinityConstraint

        # Trinity I: Structural (from AGI)
        agi_trinity = agi_output.get("trinity_structural", {})
        structural = TrinityStructural(
            physics_possible=agi_trinity.get("physics", {}).get("possible", True),
            physics_reason=agi_trinity.get("physics", {}).get("reason", ""),
            math_sound=agi_trinity.get("math", {}).get("sound", True),
            math_reason=agi_trinity.get("math", {}).get("reason", ""),
            symbol_valid=agi_trinity.get("symbol", {}).get("valid", True),
            symbol_reason=agi_trinity.get("symbol", {}).get("reason", "")
        )

        # Trinity II: Governance (from ASI)
        asi_trinity = asi_output.get("trinity_governance", {})
        governance = TrinityGovernance(
            human_witness=asi_trinity.get("human", {}).get("witness", 1.0),
            human_veto=asi_trinity.get("human", {}).get("veto", False),
            ai_witness=asi_trinity.get("ai", {}).get("witness", 1.0),
            ai_veto=asi_trinity.get("ai", {}).get("veto", False),
            institution_witness=asi_trinity.get("institution", {}).get("witness", 1.0),
            institution_veto=asi_trinity.get("institution", {}).get("veto", False),
            earth_witness=asi_trinity.get("earth", {}).get("witness", 0.95),
            earth_veto=asi_trinity.get("earth", {}).get("veto", False)
        )

        # Trinity III: Constraint (from thermodynamics)
        agi_thermo = agi_output.get("thermodynamics", {})
        asi_thermo = asi_output.get("thermodynamics", {})

        total_energy = (agi_thermo.get("energy", {}).get("total", 0) +
                       asi_thermo.get("energy", {}).get("total", 0))

        constraint = TrinityConstraint(
            time_available=1.0,
            time_consumed=agi_thermo.get("tpcp", {}).get("tau", 0) + asi_thermo.get("tpcp", {}).get("tau", 0),
            energy_budget=1.0,
            energy_consumed=total_energy,
            delta_S=agi_thermo.get("entropy", {}).get("dS", 0) + asi_thermo.get("entropy", {}).get("dS", 0)
        )

        return ThreeTrinities(
            structural=structural,
            governance=governance,
            constraint=constraint
        )

    def _check_all_floors(self, agi_output: Dict[str, Any], asi_output: Dict[str, Any],
                          eureka: EurekaResult) -> Dict[str, bool]:
        """Check all 13 constitutional floors."""
        floors = {}

        # F1: Amanah (always auditable in this system)
        floors["F1"] = True

        # F2: Truth (from AGI)
        agi_floors = agi_output.get("floor_violations", [])
        floors["F2"] = not any("F2" in v for v in agi_floors)

        # F3: Peace² (from ASI)
        asi_align = asi_output.get("align", {})
        floors["F3"] = asi_align.get("peace_squared", 0) >= 1.0 if asi_align else False

        # F4: κᵣ empathy (from ASI)
        asi_empathy = asi_output.get("empathy", {})
        floors["F4"] = asi_empathy.get("kappa_r", 0) >= 0.7 if asi_empathy else False

        # F5: Ω₀ humility
        omega = asi_align.get("omega_0", 0.04) if asi_align else 0.04
        floors["F5"] = 0.03 <= omega <= 0.05

        # F6: ΔS clarity (from thermodynamics)
        agi_thermo = agi_output.get("thermodynamics", {})
        delta_s = agi_thermo.get("entropy", {}).get("dS", 0) if agi_thermo else 0
        floors["F6"] = delta_s <= 0

        # F7: RASA (active listening)
        floors["F7"] = True  # Assume active in this context

        # F8: Tri-Witness
        asi_trinity = asi_output.get("trinity_governance", {})
        tw = asi_trinity.get("tri_witness", 0) if asi_trinity else 0
        floors["F8"] = tw >= 0.95

        # F9: Anti-Hantu (no deception)
        floors["F9"] = True  # System doesn't generate deceptive content

        # F10: Ontology Lock
        floors["F10"] = True  # System doesn't claim consciousness

        # F11: Command Auth
        floors["F11"] = True  # Verified in 000_init

        # F12: Injection Defense (from AGI)
        floors["F12"] = not any("F12" in v for v in agi_floors)

        # F13: Sovereign (deferred to 888 Judge)
        floors["F13"] = True  # Default pass, 888 Judge can override

        return floors

    # =========================================================================
    # STAGE 889: PROOF
    # =========================================================================

    def proof(self, judge_result: JudgeResult, agi_output: Dict[str, Any],
              asi_output: Dict[str, Any]) -> ProofResult:
        """
        Stage 889: PROOF — Generate cryptographic proof of judgment.

        Creates verifiable audit trail for VAULT999.
        """
        # Compute input hash
        input_hash = ProofPacket.compute_hash({
            "agi": agi_output.get("session_id", ""),
            "asi": asi_output.get("session_id", ""),
            "timestamp": time.time()
        })

        # Compute verdict hash
        verdict_hash = ProofPacket.compute_hash({
            "verdict": judge_result.verdict.value,
            "reason": judge_result.reason,
            "floor_checks": judge_result.floor_checks
        })

        # Build Merkle chain
        chain = [input_hash, verdict_hash]
        for item in self._judgment_chain:
            chain.append(item)

        # Compute Merkle root
        merkle_root = self._compute_merkle_root(chain)

        # Add to judgment chain for future proofs
        self._judgment_chain.append(merkle_root)

        proof_packet = ProofPacket(
            merkle_root=merkle_root,
            input_hash=input_hash,
            verdict_hash=verdict_hash,
            timestamp=time.time(),
            chain=chain
        )

        # Verify proof integrity
        verified = self._verify_proof(proof_packet)

        # Ready to seal if verdict is SEAL
        seal_ready = judge_result.verdict == Verdict.SEAL and verified

        return ProofResult(
            proof_packet=proof_packet,
            verified=verified,
            seal_ready=seal_ready
        )

    def _compute_merkle_root(self, items: List[str]) -> str:
        """Compute Merkle root from list of hashes."""
        if not items:
            return ProofPacket.compute_hash("empty")
        if len(items) == 1:
            return items[0]

        # Pair and hash until we have root
        while len(items) > 1:
            new_items = []
            for i in range(0, len(items), 2):
                if i + 1 < len(items):
                    combined = items[i] + items[i + 1]
                else:
                    combined = items[i] + items[i]  # Duplicate last if odd
                new_items.append(ProofPacket.compute_hash(combined))
            items = new_items

        return items[0]

    def _verify_proof(self, proof: ProofPacket) -> bool:
        """Verify proof packet integrity."""
        # Recompute Merkle root
        computed_root = self._compute_merkle_root(proof.chain)
        return computed_root == proof.merkle_root

    # =========================================================================
    # FULL PIPELINE EXECUTION
    # =========================================================================

    def execute(self, agi_output: Dict[str, Any], asi_output: Dict[str, Any]) -> APEXOutput:
        """
        Execute full APEX pipeline: EUREKA → JUDGE → PROOF

        Returns APEXOutput with final verdict and cryptographic proof.
        """
        start = time.time()
        floors_checked = []
        floor_violations = []

        # Stage 777: EUREKA
        eureka_result = self.eureka(agi_output, asi_output)
        floors_checked.append("F8_genius")

        # Stage 888: JUDGE
        judge_result = self.judge(eureka_result, agi_output, asi_output)
        floors_checked.extend(list(judge_result.floor_checks.keys()))

        # Collect floor violations
        for floor, passed in judge_result.floor_checks.items():
            if not passed:
                floor_violations.append(f"{floor}: Failed")

        # Stage 889: PROOF
        proof_result = self.proof(judge_result, agi_output, asi_output)
        floors_checked.append("F1_amanah_proof")

        # Build Three Trinities
        three_trinities = self._build_three_trinities(agi_output, asi_output, eureka_result)

        # Calculate thermodynamics
        elapsed = time.time() - start
        thermodynamics = ThermodynamicSignature(
            E_reasoning=elapsed * 0.1,
            E_cooling=0.05,  # Judgment cooling
            E_consensus=0.05,
            dS=-0.1 if judge_result.verdict == Verdict.SEAL else 0.0,
            psi_P=eureka_result.genius_index,
            delta_P=0.1 if judge_result.verdict == Verdict.SABAR else 0.0,
            omega_0=0.04,
            tau=elapsed
        )

        # Audit hash
        audit_hash = ProofPacket.compute_hash({
            "session_id": self.session_id,
            "verdict": judge_result.verdict.value,
            "merkle_root": proof_result.proof_packet.merkle_root,
            "timestamp": time.time()
        })

        return APEXOutput(
            status=judge_result.verdict.value,
            session_id=self.session_id,
            verdict=judge_result.verdict,
            eureka=eureka_result,
            judge=judge_result,
            proof=proof_result,
            three_trinities=three_trinities,
            thermodynamics=thermodynamics,
            floors_checked=floors_checked,
            floor_violations=floor_violations,
            audit_hash=audit_hash
        )


# =============================================================================
# EXPORTS
# =============================================================================

__all__ = [
    "APEXEngine",
    "APEXOutput",
    "VoidJustification",
    "ProofPacket",
    "EurekaResult",
    "JudgeResult",
    "ProofResult",
]
