"""Tests for watkins_nn.qwarp module (Grand Unifier)."""

import math
import pytest


def test_p_half_cycle_n64():
    """Pure cycle: leading term ~ ln(2)/n."""
    from watkins_nn.qwarp import p_half_cycle, LN2
    p = p_half_cycle(64)
    # Should be close to ln(2)/64 ≈ 0.0108 (leading term)
    assert abs(p - 0.01066) < 0.001


def test_p_half_star_n64():
    """Star collapse (golden spray): σ=1, κ=0."""
    from watkins_nn.qwarp import p_half_star
    p = p_half_star(64)
    assert abs(p - 0.02046) < 0.001


def test_p_half_virelaix_n64():
    """VirelaiX substrate: σ=1, κ=ρ*."""
    from watkins_nn.qwarp import p_half_virelaix
    p = p_half_virelaix(64)
    assert abs(p - 0.02040) < 0.001


def test_compute_alpha_cycle():
    """Pure cycle: σ=0 gives α=1."""
    from watkins_nn.qwarp import compute_alpha
    alpha = compute_alpha(64, sigma=0.0)
    assert abs(alpha - 1.0) < 1e-12


def test_compute_alpha_star():
    """Star: σ=1, κ=0 gives α=β*."""
    from watkins_nn.qwarp import compute_alpha, BETA_STAR
    alpha = compute_alpha(64, sigma=1.0, kappa=0.0)
    assert abs(alpha - BETA_STAR) < 1e-10


def test_convergence_table_length():
    from watkins_nn.qwarp import convergence_table
    table = convergence_table()
    assert len(table) == 7  # Default n_values has 7 entries


def test_convergence_table_monotonic():
    """p_{1/2}(n) decreases as n increases."""
    from watkins_nn.qwarp import convergence_table
    table = convergence_table()
    for i in range(len(table) - 1):
        assert table[i][1] > table[i + 1][1]


def test_term_contribution_leading():
    """Leading term k=1 dominates for large n."""
    from watkins_nn.qwarp import term_contribution, p_half_star
    t1 = term_contribution(64, k=1)
    p_full = p_half_star(64)
    # Leading term should be same order of magnitude
    assert abs(t1) > abs(p_full) * 0.5


def test_classify_regime_cycle():
    from watkins_nn.qwarp import classify_regime
    assert classify_regime(0.0, 0.0) == "cycle"


def test_classify_regime_star():
    from watkins_nn.qwarp import classify_regime
    assert classify_regime(1.0, 0.0) == "star"


def test_classify_regime_stressed():
    from watkins_nn.qwarp import classify_regime
    assert classify_regime(1.0, -0.05) == "stressed"


def test_classify_regime_virelaix():
    from watkins_nn.qwarp import classify_regime
    assert classify_regime(1.0, 0.127) == "virelaix"


def test_qualia_equilibrium_conservation():
    from watkins_nn.qwarp import QualiaBindingState
    q = QualiaBindingState.equilibrium()
    assert q.conservation_error < 1e-12


def test_qualia_equilibrium_z3():
    from watkins_nn.qwarp import QualiaBindingState
    q = QualiaBindingState.equilibrium()
    assert q.z3_symmetric


def test_qualia_integrated_information():
    from watkins_nn.qwarp import QualiaBindingState
    q = QualiaBindingState.equilibrium()
    assert abs(q.integrated_information - 0.331315) < 0.001


def test_qualia_binding_concurrence():
    from watkins_nn.qwarp import qualia_binding_concurrence, C_STAR_QUALIA
    c = qualia_binding_concurrence()
    assert abs(c - C_STAR_QUALIA) < 1e-10
    assert abs(c - 0.9717) < 0.001


def test_error_n_zero():
    from watkins_nn.qwarp import p_half_qwarp
    with pytest.raises(ValueError):
        p_half_qwarp(0)


def test_error_terms_out_of_range():
    from watkins_nn.qwarp import p_half_qwarp
    with pytest.raises(ValueError):
        p_half_qwarp(64, terms=13)
    with pytest.raises(ValueError):
        p_half_qwarp(64, terms=0)


def test_asymptotic_rate_large_n():
    """For large n, p_{1/2}(n) ~ C/n so rate approaches 1."""
    from watkins_nn.qwarp import asymptotic_rate
    rate = asymptotic_rate(256, 512, sigma=1.0, kappa=0.0)
    assert abs(rate - 1.0) < 0.05


def test_regime_threshold():
    """QWARPRegime.threshold() matches p_half_qwarp."""
    from watkins_nn.qwarp import REGIME_STAR, p_half_star
    assert abs(REGIME_STAR.threshold(64) - p_half_star(64)) < 1e-15


def test_qualia_fidelity_threshold():
    """QualiaBindingState.fidelity_threshold() works."""
    from watkins_nn.qwarp import QualiaBindingState, p_half_virelaix
    q = QualiaBindingState.equilibrium()
    p_q = q.fidelity_threshold(64)
    p_v = p_half_virelaix(64)
    assert abs(p_q - p_v) < 1e-10


def test_cycle_numerators_length():
    from watkins_nn.qwarp import CYCLE_NUMERATORS
    assert len(CYCLE_NUMERATORS) == 12
    assert CYCLE_NUMERATORS[0] == 1
    assert CYCLE_NUMERATORS[11] == 27213582085841


def test_star_greater_than_cycle():
    """Golden spray always exceeds pure cycle threshold."""
    from watkins_nn.qwarp import p_half_cycle, p_half_star
    for n in [8, 16, 32, 64, 128]:
        assert p_half_star(n) > p_half_cycle(n)
