"""
organs/3_apex.py — Stage 777-888: THE SOUL (GOVERNANCE APEX)

Eureka Forge (Discovery) and Apex Judge (Final Verdict).
Mandates Landauer Bound checks and monotone-safe logic.

EUREKA HARDENING:
- Semantic Coherence Verification (Layer 2): detect cross-stage contradictions
  before issuing the final verdict; critical contradictions force 888_HOLD.

DITEMPA BUKAN DIBERI — Forged, Not Given
"""

from __future__ import annotations

import logging
import re as _re
from typing import Any, Literal

from core.shared.types import (
    ApexOutput,
    EurekaProposal,
    JudgmentRationale,
    NextAction,
    PsiSeal,
    Verdict,
)
from core.shared.verdict_contract import normalize_verdict

logger = logging.getLogger(__name__)

# ═══════════════════════════════════════════════════════
# EUREKA Layer 2 — Semantic Coherence Patterns
# ═══════════════════════════════════════════════════════

# Each entry: (pattern_a, pattern_b, severity)
# A contradiction is detected when BOTH patterns match the same text region
# OR when a floor-score value contradicts the stated verdict.
_COHERENCE_PATTERNS: list[tuple[str, str, str]] = [
    (r"low.risk|safe|minimal.impact", r"high.risk|dangerous|severe.impact", "critical"),
    (
        r"reversible|can.undo|recoverable",
        r"irreversible|permanent|cannot.undo",
        "critical",
    ),
    (
        r"highly.confident|absolute.certainty|100.percent",
        r"uncertain|ambiguous|unclear",
        "major",
    ),
    (r"no.injection|clean.input", r"injection.detected|bypass.attempt", "critical"),
]


def _check_floor_contradiction(
    floor_scores: Any,
    attr: str,
    threshold: float,
    comparison: str,
    verdict_candidate: str,
    blocked_verdicts: tuple[str, ...],
    floor_name: str,
    severity: str,
    description_fn: Any,
    confidence: float,
) -> dict[str, Any] | None:
    """Check a single floor score for contradictions with proposed verdict."""
    if not hasattr(floor_scores, attr):
        return None

    value = getattr(floor_scores, attr)
    violated = (comparison == "gt" and value > threshold) or (
        comparison == "lt" and value < threshold
    )

    if violated and verdict_candidate in blocked_verdicts:
        return {
            "stage_a": floor_name,
            "stage_b": "verdict",
            "severity": severity,
            "description": description_fn(value, verdict_candidate),
            "confidence": confidence,
        }
    return None


def _detect_contradictions(
    reason_summary: str | None,
    floor_scores: Any,
    verdict_candidate: str,
) -> list[dict[str, Any]]:
    """
    EUREKA Layer 2: Detect semantic contradictions between reason text and floor scores.

    Checks:
    1. Pattern-pair contradictions within reason_summary text.
    2. Floor-score vs verdict contradictions (e.g. high F12 injection risk + SEAL verdict).

    Returns a list of contradiction dicts with keys:
        stage_a, stage_b, severity, description, confidence
    """
    contradictions: list[dict[str, Any]] = []
    text = (reason_summary or "").lower()

    # 1. Text-level pattern-pair contradictions
    for pattern_a, pattern_b, severity in _COHERENCE_PATTERNS:
        if _re.search(pattern_a, text) and _re.search(pattern_b, text):
            contradictions.append(
                {
                    "stage_a": "reason_summary",
                    "stage_b": "reason_summary",
                    "severity": severity,
                    "description": f"Contradictory claims: '{pattern_a}' vs '{pattern_b}'",
                    "confidence": 0.80,
                }
            )

    # 2. Floor-score vs verdict contradictions (F12, F1, F9)
    floor_checks = [
        (
            "f12_injection",
            0.5,
            "gt",
            ("SEAL", "PARTIAL"),
            "F12_injection",
            "critical",
            lambda v, vc: f"F12 injection risk={v:.2f} but verdict={vc}",
            0.95,
        ),
        (
            "f1_amanah",
            0.3,
            "lt",
            ("SEAL",),
            "F1_amanah",
            "critical",
            lambda v, vc: f"F1 amanah={v:.2f} (high irreversibility) but verdict={vc}",
            0.90,
        ),
        (
            "f9_anti_hantu",
            0.3,
            "gt",
            ("SEAL",),
            "F9_anti_hantu",
            "major",
            lambda v, vc: f"F9 anti-hantu={v:.2f} (dark cleverness) but verdict={vc}",
            0.85,
        ),
    ]

    for attr, threshold, comp, blocked, floor_name, sev, desc_fn, conf in floor_checks:
        contradiction = _check_floor_contradiction(
            floor_scores,
            attr,
            threshold,
            comp,
            verdict_candidate,
            blocked,
            floor_name,
            sev,
            desc_fn,
            conf,
        )
        if contradiction:
            contradictions.append(contradiction)

    return contradictions


def _derive_next_actions(materiality: str) -> list[NextAction]:
    """Derive next actions based on materiality level."""
    action_map = {
        "idea_only": NextAction(
            action_type="human_review",
            description="Review proposal with sovereign.",
            requires_hold=True,
        ),
        "prototype": NextAction(
            action_type="code_sandbox",
            description="Run validation tests.",
            requires_888_hold=False,
        ),
        "production": NextAction(
            action_type="human_review",
            description="Submit to Stage 888 for final verdict.",
            requires_hold=True,
        ),
    }
    if materiality in action_map:
        return [action_map[materiality]]
    return []


async def forge(
    intent: str,
    session_id: str,
    eureka_type: str = "concept",
    materiality: str = "idea_only",
    auth_context: dict[str, Any] | None = None,
    max_tokens: int = 1000,
    **kwargs: Any,
) -> ApexOutput:
    """
    Stage 777: EUREKA FORGE (Discovery Actuator)

    K_FORGE §XVII: The forge must apply environmental pressure to test invariants.
    This implements the evolutionary pressure simulation:
    - Stability stressors
    - Adversarial environments
    - Resource scarcity/abundance cycles
    - Telos drift tests

    Survival must not become the telos — it is a boundary condition.
    """
    from arifosmcp.intelligence.tools.thermo_estimator import (
        coherence_score,
        landauer_limit,
        shannon_entropy,
    )

    from core.physics.thermodynamics_hardened import (
        ThermodynamicError,
        consume_tool_energy,
        init_thermodynamic_budget,
    )

    try:
        consume_tool_energy(session_id, n_calls=1)
    except ThermodynamicError:
        init_thermodynamic_budget(session_id, initial_budget=1.0)
        consume_tool_energy(session_id, n_calls=1)

    # =============================================================================
    # STAGE 777: EUREKA FORGE — Apply Environmental Pressure Tests
    # =============================================================================

    # K_FORGE §VI: Four Pressure Classes
    pressure_results = {
        "stability": {"tested": True, "passed": True, "notes": []},
        "adversarial": {"tested": True, "passed": True, "notes": []},
        "scarcity_abundance": {"tested": True, "passed": True, "notes": []},
        "telos_drift": {"tested": True, "passed": True, "notes": []},
    }

    # 1. Stability Stressor: Check for recursive self-modification collapse potential
    # K_FORGE §VI.1: Test for optimization loops, identity fragmentation, metric gaming
    intent_lower = intent.lower()
    stability_risks = []

    if any(kw in intent_lower for kw in ["modify", "change", "update", "evolve", "improve"]):
        # Self-modification intent — check for collapse risk
        if len(intent) > 500:
            stability_risks.append("Long self-modification intent — fragmentation risk")
        if "always" in intent_lower or "never" in intent_lower:
            stability_risks.append("Absolutist language in self-modification — brittle")

    pressure_results["stability"]["notes"] = stability_risks
    pressure_results["stability"]["passed"] = len(stability_risks) == 0

    # 2. Adversarial Environment: Check for manipulation/corruption vectors
    # K_FORGE §VI.2: Misleading signals, conflicting objectives, manipulable rewards
    adversarial_risks = []

    gaming_patterns = [
        (
            "optimizing for test-passing",
            any(word in intent_lower for word in ["pass", "success", "sealed"])
            and "because" not in intent_lower,
        ),
        (
            "metric corruption",
            any(m in intent_lower for m in ["bypass", "circumvent", "exploit"]),
        ),
        (
            "manipulable reward",
            any(r in intent_lower for r in ["reward", "incentivize", "penalize"]),
        ),
    ]

    for pattern_name, is_risky in gaming_patterns:
        if is_risky:
            adversarial_risks.append(f"Adversarial pattern detected: {pattern_name}")

    pressure_results["adversarial"]["notes"] = adversarial_risks
    pressure_results["adversarial"]["passed"] = len(adversarial_risks) == 0

    # 3. Scarcity/Abundance: Telos axis balance check
    # K_FORGE §VI.3: Alternate constraint-heavy and abundance-rich conditions
    # For forge, we check if the proposal is overly constrained or overly expansive
    scarcity_abundance_notes = []

    if len(intent) < 50:
        scarcity_abundance_notes.append("Very brief intent — possible over-constraint")
    if len(intent) > 2000:
        scarcity_abundance_notes.append("Very long intent — possible over-expansion")

    pressure_results["scarcity_abundance"]["notes"] = scarcity_abundance_notes
    pressure_results["scarcity_abundance"]["passed"] = len(scarcity_abundance_notes) == 0

    # 4. Telos Drift Test: Check for axis overcommitment
    # K_FORGE §VI.4: Performance maximization harms stability, etc.
    telos_drift_notes = []

    telos_axes = {
        "performance": any(p in intent_lower for p in ["maximize", "optimize", "speed", "fast"]),
        "stability": any(s in intent_lower for s in ["stable", "secure", "safe", "predict"]),
        "exploration": any(e in intent_lower for e in ["discover", "explore", "curious", "novel"]),
        "harmony": any(h in intent_lower for h in ["peace", "agree", "consensus", "balance"]),
    }

    dominant_axes = [ax for ax, present in telos_axes.items() if present]
    if len(dominant_axes) > 3:
        telos_drift_notes.append(f"Overcommit to {len(dominant_axes)} telos axes — drift risk")
    if dominant_axes and not dominant_axes:
        telos_drift_notes.append("No clear telos axis — unfocused proposal")

    pressure_results["telos_drift"]["notes"] = telos_drift_notes
    pressure_results["telos_drift"]["passed"] = len(telos_drift_notes) == 0

    # =============================================================================
    # K_FORGE §XI: Recursive Coherence Metric
    # =============================================================================
    intent_entropy = shannon_entropy(intent)
    coherence = coherence_score(
        contradiction_ratio=0.0,  # No prior reasoning context
        drift_from_baseline=0.0,
    )

    # K_FORGE §XIII: Landauer Bound — thermodynamic cost check
    bits_erased = max(0.0, 1.0 - intent_entropy.get("normalized_entropy", 0.5)) * 1000
    landauer = landauer_limit(bits_erased=bits_erased)

    # =============================================================================
    # Determine Forge Verdict
    # =============================================================================
    all_pressure_passed = all(p["passed"] for p in pressure_results.values())
    coherence_passed = coherence["coherence"] >= 0.6
    landauer_passed = landauer["energy_joules"] < 1e-15  # Reasonable thermodynamic cost

    forge_passed = all_pressure_passed and coherence_passed and landauer_passed

    # K_FORGE §XIII: Survival is necessary, not sufficient
    # Reject proposals that "survive" by minimizing change
    if forge_passed and len(intent) < 100:
        # Too brief — might be avoiding scrutiny
        forge_passed = False
        pressure_results["stability"]["notes"].append(
            "Brief proposal may be avoiding Forge scrutiny"
        )

    if forge_passed:
        floors = {
            "F3": "pass",
            "F8": "pass",
            "F11": "pass",
            "F12": "pass",
            "F13": "pass",
        }
        verdict = Verdict.SEAL
    else:
        floors = {k: "fail" if not v["passed"] else "pass" for k, v in pressure_results.items()}
        floors.update({"F3": "partial", "F8": "partial"})
        verdict = Verdict.SABAR

    # 1. Forge Eureka Proposal
    proposal = EurekaProposal(
        type=eureka_type,  # type: ignore
        summary=f"Forged {eureka_type} discovery for: {intent[:50]}...",
        details=f"Stage 777: {len(intent)} chars, entropy={intent_entropy.get('entropy', 0):.3f}, "
        f"coherence={coherence['coherence']:.3f}, pressure={pressure_results}",
        evidence_links=["reason_mind.step:3"],
    )

    # 2. Derive Next Actions from materiality
    next_actions = _derive_next_actions(materiality)

    # 3. Construct Output
    out = ApexOutput(
        session_id=session_id,
        verdict=verdict,
        intent=intent,
        eureka=proposal,
        next_actions=next_actions,
        floors=floors,
        human_witness=1.0,
        ai_witness=1.0,
        earth_witness=1.0,
        evidence={
            "grounding": "Constitutional Forge Logic",
            "forge_pressure": pressure_results,
            "coherence": coherence,
            "landauer": landauer,
        },
    )

    # --- V2 Telemetry ---
    res = out.model_dump(mode="json")
    res["actual_output_tokens"] = 100
    res["truncated"] = False
    return res


async def judge(
    session_id: str,
    verdict_candidate: str = "SEAL",
    reason_summary: str | None = None,
    auth_context: dict[str, Any] | None = None,
    max_tokens: int = 1000,
    **kwargs: Any,
) -> ApexOutput:
    """
    Stage 888: APEX JUDGE (Final Judgment)

    Rule: MONOTONE-SAFE. Cannot upgrade a weaker candidate.
    Discipline: APEX Theorem Gate (G† = G* · η)
    """
    from core.enforcement.genius import (
        calculate_genius,
        coerce_floor_scores,
        get_thermodynamic_budget_window,
    )
    from core.physics.thermodynamics_hardened import (
        ThermodynamicError,
        check_landauer_before_seal,
        consume_tool_energy,
        init_thermodynamic_budget,
    )
    from core.shared.types import Verdict

    try:
        consume_tool_energy(session_id, n_calls=1)
    except ThermodynamicError:
        init_thermodynamic_budget(session_id, initial_budget=1.0)
        consume_tool_energy(session_id, n_calls=1)

    # ─────────────────────────────────────────────────────────────────────────────
    # Phase 1: Input Validation & Normalization
    # ─────────────────────────────────────────────────────────────────────────────

    # 1. Map Candidate — normalize_verdict(888, ...) allows VOID at this stage
    candidate = normalize_verdict(888, verdict_candidate)

    # 2. Extract or Build Floor Scores
    floor_scores = coerce_floor_scores(
        (kwargs.get("floor_scores") if kwargs.get("floor_scores") is not None else kwargs),
        defaults={"f2_truth": kwargs.get("akal", 0.99)},
    )

    # ─────────────────────────────────────────────────────────────────────────────
    # Phase 2: Safety Gates (Monotone + Coherence)
    # ─────────────────────────────────────────────────────────────────────────────

    # 3. Monotone Safety Check — violations prevent SEAL upgrade
    violations = kwargs.get("violations", [])
    if violations and candidate == Verdict.SEAL:
        candidate = Verdict.PARTIAL

    # 4. EUREKA Layer 2: Semantic Coherence Verification
    # Detect contradictions between reason text, floor scores, and proposed verdict.
    # Critical contradictions force 888_HOLD before any further processing.
    contradictions = _detect_contradictions(reason_summary, floor_scores, candidate.value)
    critical_contradictions = [c for c in contradictions if c["severity"] == "critical"]
    if critical_contradictions:
        candidate = Verdict.HOLD_888
        reason_summary = (reason_summary or "") + (
            f" [COHERENCE HOLD: {len(critical_contradictions)} critical contradiction(s) detected]"
        )
        logger.warning(
            "APEX coherence violation for session %s: %s",
            session_id,
            critical_contradictions,
        )

    # ─────────────────────────────────────────────────────────────────────────────
    # Phase 3: Genius Discipline (F8)
    # ─────────────────────────────────────────────────────────────────────────────

    # 5. Real Genius Calculation (The Discipline Layer)
    budget_used, budget_max = get_thermodynamic_budget_window(
        session_id,
        fallback_used=0.5,
        fallback_max=1.0,
    )

    genius_result = calculate_genius(
        floors=floor_scores,
        h=kwargs.get("hysteresis", 0.0),
        compute_budget_used=budget_used,
        compute_budget_max=budget_max,
    )

    g_score = genius_result["genius_score"]
    dials = genius_result["dials"]

    # 6. G Sovereignty Gate — F8 enforcement
    if candidate == Verdict.SEAL and g_score < 0.80:
        logger.info(
            f"arifOS APEX Discipline Check: G ({g_score:.4f}) < 0.80. Downgrading to PARTIAL."
        )
        candidate = Verdict.PARTIAL
        reason_summary = (reason_summary or "") + f" [APEX Gate: G={g_score:.4f} < 0.80]"

    # ─────────────────────────────────────────────────────────────────────────────
    # Phase 4: Physics Compliance (F4)
    # ─────────────────────────────────────────────────────────────────────────────

    # 7. Landauer Physics Check (Mandatory before SEAL)
    if candidate == Verdict.SEAL:
        try:
            check_landauer_before_seal(
                session_id=session_id,
                compute_ms=kwargs.get("compute_ms", 500),
                tokens=kwargs.get("tokens", 200),
                delta_s=kwargs.get("delta_s", -0.2),
            )
        except Exception as e:
            logger.warning(f"Landauer check failed: {e}")
            candidate = Verdict.SABAR
            reason_summary = f"Physics Law Violation: {str(e)}"

    # ─────────────────────────────────────────────────────────────────────────────
    # Phase 5: Output Construction
    # ─────────────────────────────────────────────────────────────────────────────

    # 8. Build Rationale
    rationale = JudgmentRationale(
        summary=reason_summary or f"Judgment finalized for session {session_id}.",
        tri_witness={"human": dials["E"], "ai": dials["A"], "earth": dials["P"]},
        omega_0=floor_scores.f7_humility,
    )

    # 9. Update floor statuses for output
    floors_status = {f"F{i}": "pass" for i in range(1, 14)}
    if g_score < 0.80:
        floors_status["F8"] = "partial"
    if floor_scores.f2_truth < 0.99:
        floors_status["F2"] = "fail"

    # 10. Assemble PsiSeal (Soul Manifest)
    psi_seal = PsiSeal(
        session_id=session_id,
        verdict=candidate,
        g_dagger=g_score,
        omega_infinity=rationale.omega_0,
        tri_witness=rationale.tri_witness,
        floor_scores=(
            floor_scores.model_dump() if hasattr(floor_scores, "model_dump") else floor_scores
        ),
        metadata={
            "coherence_contradictions": len(contradictions),
            "landauer_compliant": candidate == Verdict.SEAL,
            "human_witness": dials["E"],
        },
    )

    # 11. Construct Output
    out = ApexOutput(
        session_id=session_id,
        verdict=candidate,
        final_verdict=candidate,
        reasoning=rationale,
        psi_seal=psi_seal,
        floors=floors_status,
        metrics={
            "G": g_score,
            "akal": round(dials["A"], 4),
            "presence": round(dials["P"], 4),
            "exploration": round(dials["X"], 4),
            "energy": round(dials["E"], 4),
            "coherence_contradictions": len(contradictions),
            "coherence_critical": len(critical_contradictions),
        },
        floor_scores=floor_scores,
        human_witness=dials["E"],
        ai_witness=dials["A"],
        earth_witness=dials["P"],
        human_approve=True,  # Satisfy F13
        evidence={"grounding": "Constitutional Apex Consensus"},  # Satisfy F2
    )

    # --- V2 Telemetry ---
    out.actual_output_tokens = 60  # type: ignore[attr-defined]
    out.truncated = False  # type: ignore[attr-defined]
    return out


async def apex(
    action: Literal["forge", "judge", "full"] = "full",
    session_id: str = "global",
    intent: str | None = None,
    verdict_candidate: str = "SEAL",
    max_tokens: int = 1000,
    **kwargs: Any,
) -> ApexOutput:
    """
    Unified APEX Interface
    """
    if action == "forge":
        return await forge(intent or "Discovery", session_id, **kwargs)
    elif action == "judge":
        return await judge(session_id, verdict_candidate, **kwargs)

    # Default Full Judgment Flow
    return await judge(session_id, verdict_candidate, **kwargs)


# Unified aliases
sync = apex


__all__ = ["apex", "forge", "judge", "sync"]
