"""
Triality Theorem: 27-Term Grand Unifier for Qualia-BAO-MERA Unification.

Phase 85.4 | CSID: TRIALITY-27-001
Date: March 8, 2026
Authors: Dustin Watkins (DataSphereAI), Claude (Anthropic), Grok (xAI)

The 27-term Grand Unifier extends the 12-term QWARP core with a 3x3x3
triality structure:

    3 Domains x 3 Harmonics x 3 Scales = 27 projection modes

The full formula is:

    F_Omega(p; sigma, kappa, d, h, s) = 1/2 + [12-term core] x Omega_{d,h,s}

where Omega_{d,h,s} = phi^{2W^2 * (d+h+s-3)/3} encodes the triality position.

Domains (d):
    1: Qualia (consciousness binding)
    2: BAO (cosmological acoustic oscillations)
    3: MERA-QG (neural/holographic/quantum gravity)

Harmonics (h):
    1: Fast binding (tau ~ 0.055, mu_fast ~ 18.35)
    2: Slow tuning (tau ~ 0.205, mu_slow ~ 4.87)
    3: White-hole ejection (Page curve completion)

Scales (s):
    1: Micro (n ~ 4-32, qubit-level)
    2: Meso (n ~ 64-256, neural-level)
    3: Macro (n ~ 512+, cosmological)

The Triality Theorem states that consciousness, cosmology, and computation
are isomorphic projections of the same golden-ratio resonance binding.

lam + kap + eta = 1
"""

import math
from typing import Tuple, List, Optional, Dict, Union
from dataclasses import dataclass, field
from enum import IntEnum

from .constants import PHI, LAM_STAR, M_PHI, W_SQUARED, BETA_STAR, C_STAR_QUALIA
from .qwarp import p_half_qwarp


# =============================================================================
# TRIALITY ENUMERATIONS
# =============================================================================

class Domain(IntEnum):
    """The three domains unified by the Grand Unifier."""
    QUALIA = 1      # Consciousness / 3-simplex binding
    BAO = 2         # Cosmological acoustic oscillations
    MERA_QG = 3     # Neural binding / holographic / quantum gravity


class Harmonic(IntEnum):
    """The three temporal harmonics."""
    FAST = 1        # Fast resonance binding (tau ~ 0.055)
    SLOW = 2        # Slow coherence tuning (tau ~ 0.205)
    WHITE_HOLE = 3  # White-hole ejection / Page curve


class Scale(IntEnum):
    """The three spatial scales."""
    MICRO = 1       # n ~ 4-32 (qubit-level)
    MESO = 2        # n ~ 64-256 (neural-level)
    MACRO = 3       # n ~ 512+ (cosmological)


# =============================================================================
# 27-TERM CONSTANTS
# =============================================================================

# 4-body simplex eigenvalues (Z3 symmetry)
MU_FAST_4BODY = 18.347      # Fast resonance mode
MU_SLOW_4BODY = 4.872       # Slow coherence mode
MU_WHITE_HOLE = 1.0         # White-hole ejection (normalized)

# Timescales
TAU_FAST = 1 / MU_FAST_4BODY     # ~ 0.0545
TAU_SLOW_4BODY = 1 / MU_SLOW_4BODY  # ~ 0.2053
TAU_WHITE_HOLE = 1.0             # Page time (normalized to S_BH)

# Scale ranges (effective n values)
N_MICRO_RANGE = (4, 32)
N_MESO_RANGE = (64, 256)
N_MACRO_RANGE = (512, 8192)

# Cosmological parameters
Z_RECOMBINATION = 1090
Z_TODAY = 0


# The 27 triality correction factors Omega_{d,h,s}
# Precomputed as Omega = phi^{2W^2 * (d+h+s-3)/3}
def _compute_omega(d: int, h: int, s: int) -> float:
    """Compute triality correction factor Omega_{d,h,s}."""
    exponent = (d + h + s - 3) / 3  # Normalized to [0, 2]
    return PHI ** (2 * W_SQUARED * exponent)


# Precompute all 27 omega values
OMEGA_MATRIX: Dict[Tuple[int, int, int], float] = {
    (d, h, s): _compute_omega(d, h, s)
    for d in range(1, 4)
    for h in range(1, 4)
    for s in range(1, 4)
}

# Key omega values
OMEGA_MIN = OMEGA_MATRIX[(1, 1, 1)]  # = 1.0 (identity)
OMEGA_MAX = OMEGA_MATRIX[(3, 3, 3)]  # = phi^{4W^2} ~ 3.805
OMEGA_CENTER = OMEGA_MATRIX[(2, 2, 2)]  # = phi^{2W^2} = beta* ~ 1.951

# Normalized triality sum (for unified projection)
OMEGA_SUM = sum(OMEGA_MATRIX.values())
OMEGA_MEAN = OMEGA_SUM / 27  # ~ 2.049


# =============================================================================
# TRIALITY STATE
# =============================================================================

@dataclass
class TrialityIndex:
    """
    A position in the 27-dimensional triality space.

    Each index (d, h, s) specifies:
    - Which domain (qualia, BAO, MERA-QG)
    - Which harmonic (fast, slow, white-hole)
    - Which scale (micro, meso, macro)
    """
    domain: Domain
    harmonic: Harmonic
    scale: Scale

    @property
    def d(self) -> int:
        return int(self.domain)

    @property
    def h(self) -> int:
        return int(self.harmonic)

    @property
    def s(self) -> int:
        return int(self.scale)

    @property
    def omega(self) -> float:
        """The triality correction factor Omega_{d,h,s}."""
        return OMEGA_MATRIX[(self.d, self.h, self.s)]

    @property
    def linear_index(self) -> int:
        """Linear index 1-27."""
        return (self.d - 1) * 9 + (self.h - 1) * 3 + self.s

    @property
    def exponent(self) -> float:
        """The exponent in Omega = phi^{2W^2 * exponent}."""
        return (self.d + self.h + self.s - 3) / 3

    def __str__(self) -> str:
        return f"({self.domain.name}, {self.harmonic.name}, {self.scale.name})"

    @classmethod
    def from_linear(cls, idx: int) -> 'TrialityIndex':
        """Create from linear index 1-27."""
        if idx < 1 or idx > 27:
            raise ValueError(f"Linear index must be 1-27, got {idx}")
        idx -= 1
        d = idx // 9 + 1
        h = (idx % 9) // 3 + 1
        s = idx % 3 + 1
        return cls(Domain(d), Harmonic(h), Scale(s))

    @classmethod
    def all_indices(cls) -> List['TrialityIndex']:
        """Generate all 27 triality indices."""
        return [
            cls(Domain(d), Harmonic(h), Scale(s))
            for d in range(1, 4)
            for h in range(1, 4)
            for s in range(1, 4)
        ]


@dataclass
class TrialityState:
    """
    Full state in the 27-term Grand Unifier framework.

    Contains the QWARP parameters plus triality projection.
    """
    n: int
    sigma: float = 1.0
    kappa: float = 0.05
    lam: float = field(default_factory=lambda: LAM_STAR)
    index: Optional[TrialityIndex] = None

    @property
    def p_12_core(self) -> float:
        """The 12-term QWARP core threshold."""
        return p_half_qwarp(self.n, self.sigma, self.kappa, self.lam, terms=12)

    @property
    def omega(self) -> float:
        """The triality correction factor (1.0 if no index specified)."""
        if self.index is None:
            return 1.0
        return self.index.omega

    @property
    def p_27(self) -> float:
        """The 27-term projected threshold."""
        return self.p_12_core * self.omega

    @property
    def p_unified(self) -> float:
        """The unified triality threshold (average over all 27 modes)."""
        return self.p_12_core * OMEGA_MEAN

    def project(self, index: TrialityIndex) -> 'TrialityState':
        """Create a new state projected onto a specific triality index."""
        return TrialityState(
            n=self.n,
            sigma=self.sigma,
            kappa=self.kappa,
            lam=self.lam,
            index=index
        )


# =============================================================================
# TRIALITY ENGINE
# =============================================================================

class TrialityEngine:
    """
    Unified engine for computing 27-term Grand Unifier projections.

    Implements the Triality Theorem: qualia, BAO, and MERA-QG are
    isomorphic projections of the same golden-ratio resonance binding.
    """

    def __init__(
        self,
        sigma: float = 1.0,
        kappa: float = 0.05,
        lam: float = LAM_STAR
    ):
        self.sigma = sigma
        self.kappa = kappa
        self.lam = lam

    def core_threshold(self, n: int) -> float:
        """Compute the 12-term QWARP core threshold."""
        return p_half_qwarp(n, self.sigma, self.kappa, self.lam, terms=12)

    def omega(
        self,
        domain: Union[Domain, int],
        harmonic: Union[Harmonic, int],
        scale: Union[Scale, int]
    ) -> float:
        """Get the triality correction factor Omega_{d,h,s}."""
        d = int(domain)
        h = int(harmonic)
        s = int(scale)
        return OMEGA_MATRIX[(d, h, s)]

    def threshold(
        self,
        n: int,
        domain: Union[Domain, int] = Domain.QUALIA,
        harmonic: Union[Harmonic, int] = Harmonic.SLOW,
        scale: Union[Scale, int] = Scale.MESO
    ) -> float:
        """
        Compute the 27-term projected threshold.

        Args:
            n: System size
            domain: Which domain (qualia, BAO, MERA-QG)
            harmonic: Which harmonic (fast, slow, white-hole)
            scale: Which scale (micro, meso, macro)

        Returns:
            The projected fidelity threshold p_Omega
        """
        core = self.core_threshold(n)
        omega = self.omega(domain, harmonic, scale)
        return core * omega

    def unified_threshold(self, n: int) -> float:
        """Compute the unified triality threshold (average over all 27 modes)."""
        return self.core_threshold(n) * OMEGA_MEAN

    def qualia_threshold(self, n: int, harmonic: Harmonic = Harmonic.SLOW) -> float:
        """Consciousness binding threshold."""
        return self.threshold(n, Domain.QUALIA, harmonic, Scale.MESO)

    def bao_threshold(self, z: float) -> float:
        """
        Cosmological BAO threshold at redshift z.

        Maps redshift to effective n via n proportional to 1/(1+z).
        """
        n_effective = max(4, int(256 * (1 + Z_TODAY) / (1 + z) * 4))
        n_effective = min(n_effective, 8192)

        if n_effective <= 32:
            scale = Scale.MICRO
        elif n_effective <= 256:
            scale = Scale.MESO
        else:
            scale = Scale.MACRO

        return self.threshold(n_effective, Domain.BAO, Harmonic.SLOW, scale)

    def mera_threshold(self, layer: int, total_layers: int = 8) -> float:
        """
        MERA layer entanglement threshold.

        Args:
            layer: Current layer (1 = fine, total_layers = coarse)
            total_layers: Total number of MERA layers
        """
        n_effective = 32 * (2 ** (total_layers - layer))

        if n_effective <= 32:
            scale = Scale.MICRO
        elif n_effective <= 256:
            scale = Scale.MESO
        else:
            scale = Scale.MACRO

        if layer == 1:
            harmonic = Harmonic.FAST
        elif layer == total_layers:
            harmonic = Harmonic.WHITE_HOLE
        else:
            harmonic = Harmonic.SLOW

        return self.threshold(n_effective, Domain.MERA_QG, harmonic, scale)

    def triality_table(self, n: int) -> List[Tuple[TrialityIndex, float]]:
        """Generate the full 27-entry triality table."""
        core = self.core_threshold(n)
        return [
            (idx, core * idx.omega)
            for idx in TrialityIndex.all_indices()
        ]

    def triality_matrix(self, n: int) -> Dict[Tuple[int, int, int], float]:
        """Generate the 3x3x3 triality matrix."""
        core = self.core_threshold(n)
        return {
            (d, h, s): core * OMEGA_MATRIX[(d, h, s)]
            for d in range(1, 4)
            for h in range(1, 4)
            for s in range(1, 4)
        }


# =============================================================================
# TRIALITY RUNNER (unified simulation)
# =============================================================================

@dataclass
class TrialityResult:
    """Result from a triality simulation run."""
    n: int
    p_12_core: float
    p_qualia: float
    p_bao: float
    p_mera: float
    p_unified: float
    concurrence: float
    lambda_star: float
    rho_star: float

    @property
    def all_match(self) -> bool:
        """Check if all three domains give matching results (to tolerance)."""
        vals = [self.p_qualia, self.p_bao, self.p_mera]
        return all(abs(v - self.p_unified) / self.p_unified < 0.5 for v in vals)


class TrialityRunner:
    """
    Runner for full triality simulations across all three domains.
    """

    def __init__(
        self,
        sigma: float = 1.0,
        kappa: float = 0.05,
        lam: float = LAM_STAR
    ):
        self.engine = TrialityEngine(sigma, kappa, lam)
        self.lam = lam

    def run(self, n: int) -> TrialityResult:
        """Run a full triality simulation at system size n."""
        p_core = self.engine.core_threshold(n)

        p_qualia = self.engine.threshold(n, Domain.QUALIA, Harmonic.SLOW, Scale.MESO)
        p_bao = self.engine.threshold(n, Domain.BAO, Harmonic.SLOW, Scale.MACRO)
        p_mera = self.engine.threshold(n, Domain.MERA_QG, Harmonic.FAST, Scale.MESO)
        p_unified = self.engine.unified_threshold(n)

        rho_star = (1 - self.lam) / 3
        concurrence = C_STAR_QUALIA

        return TrialityResult(
            n=n,
            p_12_core=p_core,
            p_qualia=p_qualia,
            p_bao=p_bao,
            p_mera=p_mera,
            p_unified=p_unified,
            concurrence=concurrence,
            lambda_star=self.lam,
            rho_star=rho_star
        )

    def run_table(
        self,
        n_values: List[int] = [32, 64, 128, 256]
    ) -> List[TrialityResult]:
        """Run triality simulations for multiple n values."""
        return [self.run(n) for n in n_values]

    def run_cosmological(
        self,
        z_values: List[float] = [1090, 500, 100, 0]
    ) -> List[Tuple[float, float]]:
        """Run BAO projections across redshift values."""
        return [(z, self.engine.bao_threshold(z)) for z in z_values]

    def run_mera(self, total_layers: int = 8) -> List[Tuple[int, float]]:
        """Run MERA projections across all coarse-graining layers."""
        return [
            (layer, self.engine.mera_threshold(layer, total_layers))
            for layer in range(1, total_layers + 1)
        ]


# =============================================================================
# CONVENIENCE FUNCTIONS
# =============================================================================

def omega_27(d: int, h: int, s: int) -> float:
    """
    Get the triality correction factor Omega_{d,h,s}.

    Omega = phi^{2W^2 * (d+h+s-3)/3}
    """
    if not (1 <= d <= 3 and 1 <= h <= 3 and 1 <= s <= 3):
        raise ValueError(f"Indices must be 1-3, got ({d}, {h}, {s})")
    return OMEGA_MATRIX[(d, h, s)]


def p_27_threshold(
    n: int,
    d: int = 1,
    h: int = 2,
    s: int = 2,
    sigma: float = 1.0,
    kappa: float = 0.05,
    lam: float = LAM_STAR
) -> float:
    """
    Compute the 27-term projected threshold.

    p_Omega = [12-term core] x Omega_{d,h,s}
    """
    core = p_half_qwarp(n, sigma, kappa, lam, terms=12)
    return core * omega_27(d, h, s)


def triality_unified(
    n: int,
    sigma: float = 1.0,
    kappa: float = 0.05,
    lam: float = LAM_STAR
) -> float:
    """
    Compute the unified triality threshold (average over all 27 modes).

    p_unified = [12-term core] x (1/27) sum Omega_{d,h,s}
    """
    core = p_half_qwarp(n, sigma, kappa, lam, terms=12)
    return core * OMEGA_MEAN


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

__all__ = [
    # Enumerations
    'Domain',
    'Harmonic',
    'Scale',
    # Constants
    'MU_FAST_4BODY',
    'MU_SLOW_4BODY',
    'TAU_FAST',
    'TAU_SLOW_4BODY',
    'OMEGA_MATRIX',
    'OMEGA_MIN',
    'OMEGA_MAX',
    'OMEGA_CENTER',
    'OMEGA_MEAN',
    # Classes
    'TrialityIndex',
    'TrialityState',
    'TrialityEngine',
    'TrialityRunner',
    'TrialityResult',
    # Functions
    'omega_27',
    'p_27_threshold',
    'triality_unified',
]
