"""
Self-Verifying Witness — Base classes for receipts that carry their own correctness proofs.

This is the foundational "DNA" for the computational physics layer. Every receipt
becomes a mathematical object that proves its own validity.

Design:
- Proof: Constructive evidence that a claim holds
- ProofOfImpossibility: Constructive evidence that no valid state exists
- SelfVerifyingWitness: Base for receipts with embedded proofs

Usage:
    class ProphecyStone(SelfVerifyingWitness):
        @property
        def proof(self) -> Proof:
            return Proof(
                claim="Prophecy satisfies all gates",
                evidence={
                    "calibrated": self._calibration_witness(),
                    "dignified": self._dignity_witness(),
                },
                reasoning="Each gate verified independently"
            )
"""
from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional, Tuple, Union

import numpy as np


@dataclass
class GateWitness:
    """Evidence that a specific gate constraint was satisfied (or violated)."""
    
    gate_name: str
    passed: bool
    value: float
    threshold: float
    operator: str  # "<=", ">=", "==", "!="
    proof: str  # Human-readable explanation
    metadata: Dict[str, Any] = field(default_factory=dict)
    
    def verify(self) -> bool:
        """Check if witness claim is self-consistent."""
        if self.operator == "<=":
            return (self.value <= self.threshold) == self.passed
        elif self.operator == ">=":
            return (self.value >= self.threshold) == self.passed
        elif self.operator == "==":
            return (abs(self.value - self.threshold) < 1e-9) == self.passed
        elif self.operator == "!=":
            return (abs(self.value - self.threshold) >= 1e-9) == self.passed
        return False


@dataclass
class Proof:
    """Constructive proof of a claim with verifiable evidence."""
    
    claim: str
    evidence: Dict[str, Any]  # Gate witnesses, metrics, etc.
    reasoning: str
    verified_at: Optional[datetime] = None
    
    def __post_init__(self):
        if self.verified_at is None:
            self.verified_at = datetime.now(timezone.utc)
    
    def check(self, data: Dict[str, Any]) -> bool:
        """Verify proof against provided data.
        
        Returns True if all evidence items are consistent with data.
        """
        for key, constraint in self.evidence.items():
            if not self._verify_constraint(data.get(key), constraint):
                return False
        return True
    
    def _verify_constraint(self, value: Any, constraint: Any) -> bool:
        """Verify individual constraint."""
        if isinstance(constraint, dict):
            # GateWitness-style constraint
            if "threshold" in constraint and "satisfied" in constraint:
                threshold = constraint["threshold"]
                expected_satisfied = constraint["satisfied"]
                actual_value = constraint.get("value", value)
                
                # Reconstruct gate check
                if actual_value is None:
                    return False
                
                # Infer operator from context (could be explicit)
                operator = constraint.get("operator", "<=")
                if operator == "<=":
                    actual_satisfied = actual_value <= threshold
                elif operator == ">=":
                    actual_satisfied = actual_value >= threshold
                else:
                    return False
                
                return actual_satisfied == expected_satisfied
        
        # Simple equality check
        return value == constraint
    
    def explain(self) -> str:
        """Human-readable explanation of proof."""
        lines = [f"Claim: {self.claim}", f"Reasoning: {self.reasoning}", ""]
        lines.append("Evidence:")
        for key, evidence in self.evidence.items():
            if isinstance(evidence, dict) and "proof" in evidence:
                lines.append(f"  {key}: {evidence['proof']}")
            else:
                lines.append(f"  {key}: {evidence}")
        return "\n".join(lines)


@dataclass
class ProofOfImpossibility:
    """Constructive proof that no valid solution exists within search space.
    
    Used for RefusalStones to prove why no dignified/calibrated prophecy
    could be constructed from available data.
    """
    
    search_space: List[Any]  # What was attempted
    failures: List[Tuple[Any, str]]  # (attempt, reason_failed)
    nearest_valid: Any  # Closest point to validity
    gap: float  # Distance to validity (in relevant metric space)
    certificate: str  # Why gap is unbridgeable
    metadata: Dict[str, Any] = field(default_factory=dict)
    
    def explain(self) -> str:
        """Human-readable explanation of impossibility."""
        lines = [
            f"No valid solution exists.",
            f"Search space: {len(self.search_space)} attempts",
            f"Gap to validity: {self.gap:.4f}",
            f"Certificate: {self.certificate}",
            "",
            "Failure summary:"
        ]
        
        # Group failures by reason
        reason_counts: Dict[str, int] = {}
        for _, reason in self.failures:
            reason_counts[reason] = reason_counts.get(reason, 0) + 1
        
        for reason, count in sorted(reason_counts.items(), key=lambda x: -x[1]):
            lines.append(f"  {reason}: {count} attempts")
        
        return "\n".join(lines)


class SelfVerifyingWitness(ABC):
    """Base class for receipts that carry their own correctness proof.
    
    This is the foundational pattern that enables computational physics:
    - Receipts are theorems (type signature is the claim)
    - Proofs are constructive evidence
    - Verification is deterministic (anyone can check)
    - No trust required (math is self-evident)
    
    Subclasses must implement:
    - proof: Return Proof or ProofOfImpossibility
    - data: Return raw data for verification
    """
    
    @property
    @abstractmethod
    def proof(self) -> Union[Proof, ProofOfImpossibility]:
        """Return constructive proof of correctness (or impossibility)."""
        pass
    
    def verify(self) -> bool:
        """Anyone can verify without trusting issuer.
        
        Returns True if proof is valid and consistent with data.
        """
        proof = self.proof
        
        # ProofOfImpossibility is valid by construction
        if isinstance(proof, ProofOfImpossibility):
            return len(proof.failures) > 0 and proof.gap > 0
        
        # Regular Proof must check against data
        return proof.check(self.data)
    
    @property
    @abstractmethod
    def data(self) -> Dict[str, Any]:
        """Raw data for verification.
        
        Should include all values referenced in proof evidence.
        """
        pass
    
    def explain(self) -> str:
        """Human-readable explanation of this witness."""
        return self.proof.explain()


def create_calibration_witness(
    ece: float,
    ece_threshold: float = 0.03,
    coverage: Optional[float] = None,
    coverage_target: float = 0.90,
    n_samples: Optional[int] = None
) -> GateWitness:
    """Create a calibration gate witness."""
    passed = ece <= ece_threshold
    
    metadata = {}
    if coverage is not None:
        metadata["coverage"] = coverage
        metadata["coverage_target"] = coverage_target
        metadata["coverage_ok"] = abs(coverage - coverage_target) <= 0.02
    if n_samples is not None:
        metadata["n_samples"] = n_samples
    
    proof_text = f"ECE={ece:.4f} {'≤' if passed else '>'} {ece_threshold}"
    if coverage is not None:
        coverage_status = "✓" if metadata["coverage_ok"] else "✗"
        proof_text += f" | Coverage={coverage:.3f} (target={coverage_target}) {coverage_status}"
    
    return GateWitness(
        gate_name="calibration",
        passed=passed,
        value=ece,
        threshold=ece_threshold,
        operator="<=",
        proof=proof_text,
        metadata=metadata
    )


def create_dignity_witness(
    dwf: float,
    dwf_threshold: float = 0.70,
    entropy: Optional[float] = None,
    extremity: Optional[float] = None
) -> GateWitness:
    """Create a dignity gate witness."""
    passed = dwf >= dwf_threshold
    
    metadata = {}
    if entropy is not None:
        metadata["entropy"] = entropy
    if extremity is not None:
        metadata["extremity"] = extremity
    
    proof_text = f"DWF={dwf:.3f} {'≥' if passed else '<'} {dwf_threshold}"
    if entropy is not None and extremity is not None:
        proof_text += f" | H={entropy:.3f} × (1-|p-0.5|)={extremity:.3f}"
    
    return GateWitness(
        gate_name="dignity",
        passed=passed,
        value=dwf,
        threshold=dwf_threshold,
        operator=">=",
        proof=proof_text,
        metadata=metadata
    )


def create_evhd_witness(
    rho: float,
    rho_threshold: float = 0.60,
    support: Optional[int] = None,
    min_support: int = 100
) -> GateWitness:
    """Create an EVHD monotonicity witness."""
    passed = rho >= rho_threshold
    
    metadata = {}
    if support is not None:
        metadata["support"] = support
        metadata["min_support"] = min_support
        metadata["support_ok"] = support >= min_support
    
    proof_text = f"ρ={rho:.3f} {'≥' if passed else '<'} {rho_threshold}"
    if support is not None:
        support_status = "✓" if metadata.get("support_ok") else "✗"
        proof_text += f" | n={support} (min={min_support}) {support_status}"
    
    return GateWitness(
        gate_name="evhd_monotonicity",
        passed=passed,
        value=rho,
        threshold=rho_threshold,
        operator=">=",
        proof=proof_text,
        metadata=metadata
    )


def create_coherence_witness(
    coherence_score: float,
    coherence_threshold: float = 0.50,
    phi: Optional[float] = None,
    xi: Optional[float] = None,
    chi: Optional[float] = None
) -> GateWitness:
    """Create a coherence gate witness."""
    passed = coherence_score >= coherence_threshold
    
    metadata = {}
    if phi is not None:
        metadata["phi"] = phi
    if xi is not None:
        metadata["xi"] = xi
    if chi is not None:
        metadata["chi"] = chi
    
    proof_text = f"ΔC={coherence_score:.3f} {'≥' if passed else '<'} {coherence_threshold}"
    if phi is not None and xi is not None and chi is not None:
        proof_text += f" | φ={phi:.2f} ξ={xi:.2f} χ={chi:.2f}"
    
    return GateWitness(
        gate_name="coherence",
        passed=passed,
        value=coherence_score,
        threshold=coherence_threshold,
        operator=">=",
        proof=proof_text,
        metadata=metadata
    )
