/-
  ChiralitySpace.lean — The Full 4D Descriptor: Phase × Chirality × Direction × Regime

  The Hachimoji state descriptor is NOT just 8 regimes. It is a
  4-dimensional structure:

    Phase      : 8 values (0°, 45°, 90°, 135°, 180°, 225°, 270°, 315°)
    Chirality  : 3 values (ambidextrous, left, right)
    Direction  : 2 values (forward, reverse)
    Regime     : 3 values (beautiful, ugly, horrible)

  Total states: 8 × 3 × 2 × 3 = 144 distinct states.
  But the mapping is STRUCTURALLY CONSTRAINED: not all combinations
  are valid. The constraints encode the physics of the system.

  In the universal encoding context, each of the 50 tokens carries
  a chirality (left-handed usage vs right-handed usage) and the
  full expression has a direction (forward = constructive math,
  reverse = deconstructive/critical math). This multiplies the
  2^50 token address space by the chirality space, giving
  2^50 × 144 ≈ 1.6 × 10^17 distinct classified expressions.

  The chirality lattice encodes at 45° increments on ℤ/360ℤ,
  matching the phase-quantized structure from the chaos game
  documentation.
-/

import Mathlib
import universal_encoding.UniversalMathEncoding

namespace ChiralitySpace

open UniversalMathEncoding

-- =================================================================
-- §1. PHASE (8 values, 45° increments)
-- =================================================================

inductive Phase
  | p0    -- 0°   : origin, aligned
  | p45   -- 45°  : first quadrant
  | p90   -- 90°  : orthogonal
  | p135  -- 135° : second quadrant
  | p180  -- 180° : opposition
  | p225  -- 225° : third quadrant
  | p270  -- 270° : reverse orthogonal
  | p315  -- 315° : fourth quadrant
  deriving DecidableEq, BEq, Repr, Fintype

def phaseToDegrees : Phase → ℕ
  | .p0 => 0 | .p45 => 45 | .p90 => 90 | .p135 => 135
  | .p180 => 180 | .p225 => 225 | .p270 => 270 | .p315 => 315

-- =================================================================
-- §2. CHIRALITY (3 values)
-- =================================================================

inductive Chirality
  | ambidextrous  -- no handedness (axis-aligned, balanced)
  | left          -- left-handed (forward half-plane)
  | right         -- right-handed (reverse half-plane)
  deriving DecidableEq, BEq, Repr, Fintype

-- =================================================================
-- §3. DIRECTION (2 values)
-- =================================================================

inductive Direction
  | forward   -- constructive, building up
  | reverse   -- deconstructive, taking apart
  deriving DecidableEq, BEq, Repr, Fintype

-- =================================================================
-- §4. REGIME (3 values)
-- =================================================================

inductive Regime
  | beautiful  -- well-behaved, convergent, canonical
  | ugly       -- complicated but manageable
  | horrible   -- divergent, paradoxical, pathological
  deriving DecidableEq, BEq, Repr, Fintype

-- =================================================================
-- §5. STRUCTURAL CONSISTENCY CONSTRAINTS
-- =================================================================

/-- The 4D descriptor must satisfy structural consistency rules.
    These are not arbitrary — they encode the geometric and
    physical structure of the system.

    Rule 1: Phase 0° and 180° must be ambidextrous (axis-aligned).
    Rule 2: Forward direction only in phases < 180°.
    Rule 3: Reverse direction only in phases ≥ 180°.
    Rule 4: Left chirality only in forward half-plane (0°-180°).
    Rule 5: Right chirality only in reverse half-plane (180°-360°).
    Rule 6: Beautiful regime only in phases 0°-90°.
    Rule 7: Horrible regime only in phases 180°-360°.
    Rule 8: Ambidextrous only at axis phases (0°, 180°). -/

def isConsistent (ph : Phase) (ch : Chirality) (dir : Direction) (reg : Regime) : Bool :=
  let deg := phaseToDegrees ph
  -- Rule 1: ambidextrous only at axis phases (0°, 180°)
  (ch != .ambidextrous || deg == 0 || deg == 180) &&
  -- Rule 2: forward only in phases < 180°
  (dir != .forward || deg < 180) &&
  -- Rule 3: reverse only in phases ≥ 180°
  (dir != .reverse || deg ≥ 180) &&
  -- Rule 4: left only in forward half-plane
  (ch != .left || deg < 180) &&
  -- Rule 5: right only in reverse half-plane
  (ch != .right || deg ≥ 180) &&
  -- Rule 6: beautiful only in phases 0°-90°
  (reg != .beautiful || deg ≤ 90) &&
  -- Rule 7: horrible only in phases 180°-360°
  (reg != .horrible || deg ≥ 180)

/-- Theorem: consistent descriptors form a proper subset of
    the full 4D space. The full space has 8×3×2×3 = 144 states.
    The consistent subset has fewer (exact count computable).
    
    Proof: native_decide computes the exact cardinality of the
    consistent subset by enumerating all 144 possibilities and
    counting those that satisfy all 8 constraints. -/
theorem consistent_count_lt_full :
    (Finset.filter (λ (p : Phase × Chirality × Direction × Regime) =>
      match p with | (ph, ch, dir, reg) => isConsistent ph ch dir reg)
      (Finset.univ : Finset (Phase × Chirality × Direction × Regime))).card < 144 := by
  decide

-- =================================================================
-- §6. CHIRALITY ASSIGNMENT PER TOKEN
-- =================================================================

/-- Each of the 50 MathTokens has an intrinsic chirality based on
    its mathematical meaning. This is NOT arbitrary — it reflects
    the structural handedness of the operation.

    Left-handed operations: constructive, building up
      - addition, integration, summation, limits, expectation
    Right-handed operations: deconstructive, analyzing
      - differentiation, negation, implication, variance
    Ambidextrous operations: symmetric, no inherent handedness
      - equality, equivalence, constants, variables -/

def tokenChirality : {n : Fin 50} → MathToken n → Chirality
  -- Group 0 (Φ): ambidextrous — constants and variables are symmetric
  | ⟨0,_⟩,  _ => .ambidextrous   -- π
  | ⟨1,_⟩,  _ => .ambidextrous   -- e
  | ⟨2,_⟩,  _ => .ambidextrous   -- i
  | ⟨3,_⟩,  _ => .ambidextrous   -- γ
  | ⟨4,_⟩,  _ => .ambidextrous   -- x
  | ⟨5,_⟩,  _ => .ambidextrous   -- n
  | ⟨6,_⟩,  _ => .ambidextrous   -- + (addition is symmetric)

  -- Group 1 (Λ): mixed
  | ⟨7,_⟩,  _ => .left            -- × (multiplication builds up)
  | ⟨8,_⟩,  _ => .right           -- ÷ (division analyzes)
  | ⟨9,_⟩,  _ => .left            -- ^ (exponentiation grows)
  | ⟨10,_⟩, _ => .ambidextrous    -- √ (symmetric: √ and square)
  | ⟨11,_⟩, _ => .right           -- |·| (norm analyzes)
  | ⟨12,_⟩, _ => .right           -- d/dx (differentiation takes apart)
  | ⟨13,_⟩, _ => .left            -- ∫ (integration builds up)

  -- Group 2 (Ρ): mostly left (constructive calculus)
  | ⟨14,_⟩, _ => .left            -- ∫∫...∫ (multiple integration)
  | ⟨15,_⟩, _ => .left            -- lim (limit constructs)
  | ⟨16,_⟩, _ => .left            -- Σ (summation accumulates)
  | ⟨17,_⟩, _ => .left            -- ∏ (product accumulates)
  | ⟨18,_⟩, _ => .right           -- ODE (differential equation analyzes)
  | ⟨19,_⟩, _ => .right           -- higher-order ODE
  | ⟨20,_⟩, _ => .ambidextrous    -- ∇² (Laplacian is symmetric)

  -- Group 3 (Κ): mixed (probability)
  | ⟨21,_⟩, _ => .left            -- 𝔼 (expectation accumulates)
  | ⟨22,_⟩, _ => .right           -- Var (variance measures spread)
  | ⟨23,_⟩, _ => .right           -- P(·|·) (conditional analyzes)
  | ⟨24,_⟩, _ => .ambidextrous    -- Lebesgue measure
  | ⟨25,_⟩, _ => .ambidextrous    -- Borel σ-algebra
  | ⟨26,_⟩, _ => .ambidextrous    -- continuous (symmetric concept)
  | ⟨27,_⟩, _ => .ambidextrous    -- measurable (symmetric concept)

  -- Group 4 (Ω): mostly right (logic deconstructs)
  | ⟨28,_⟩, _ => .left            -- ∀ (universal quantifier builds)
  | ⟨29,_⟩, _ => .left            -- ∃ (existential constructs)
  | ⟨30,_⟩, _ => .ambidextrous    -- ∅ (empty set)
  | ⟨31,_⟩, _ => .right           -- 𝒫 (power set analyzes structure)
  | ⟨32,_⟩, _ => .right           -- → (implication is directional)
  | ⟨33,_⟩, _ => .right           -- ¬ (negation reverses)
  | ⟨34,_⟩, _ => .ambidextrous    -- ↔ (equivalence is symmetric)

  -- Group 5 (Σ): ambidextrous (symmetry group)
  | ⟨35,_⟩, _ => .ambidextrous    -- algebraic variety
  | ⟨36,_⟩, _ => .ambidextrous    -- scheme
  | ⟨37,_⟩, _ => .ambidextrous    -- sheaf cohomology
  | ⟨38,_⟩, _ => .ambidextrous    -- symmetry group
  | ⟨39,_⟩, _ => .ambidextrous    -- group representation
  | ⟨40,_⟩, _ => .ambidextrous    -- homology
  | ⟨41,_⟩, _ => .ambidextrous    -- cohomology

  -- Group 6 (Π): mixed (number theory)
  | ⟨42,_⟩, _ => .ambidextrous    -- prime (fundamental, no handedness)
  | ⟨43,_⟩, _ => .right           -- ζ(s) (analytic continuation deconstructs)
  | ⟨44,_⟩, _ => .right           -- L-function
  | ⟨45,_⟩, _ => .ambidextrous    -- conductor
  | ⟨46,_⟩, _ => .ambidextrous    -- Galois group
  | ⟨47,_⟩, _ => .left            -- modular form (constructs)
  | ⟨48,_⟩, _ => .ambidextrous    -- motive

  -- Group 7 (Ζ): undefined
  | ⟨49,_⟩, _ => .ambidextrous    -- UNDEFINED

/-- Variant of tokenChirality that works directly on Fin 50 indices.
    This avoids the need to construct a MathToken value. -/
def tokenChiralityOfFin (i : Fin 50) : Chirality :=
  match i with
  -- Group 0 (Φ): ambidextrous
  | ⟨0,_⟩  => .ambidextrous | ⟨1,_⟩  => .ambidextrous
  | ⟨2,_⟩  => .ambidextrous | ⟨3,_⟩  => .ambidextrous
  | ⟨4,_⟩  => .ambidextrous | ⟨5,_⟩  => .ambidextrous
  | ⟨6,_⟩  => .ambidextrous
  -- Group 1 (Λ): mixed
  | ⟨7,_⟩  => .left         | ⟨8,_⟩  => .right
  | ⟨9,_⟩  => .left         | ⟨10,_⟩ => .ambidextrous
  | ⟨11,_⟩ => .right        | ⟨12,_⟩ => .right
  | ⟨13,_⟩ => .left
  -- Group 2 (Ρ): mostly left
  | ⟨14,_⟩ => .left         | ⟨15,_⟩ => .left
  | ⟨16,_⟩ => .left         | ⟨17,_⟩ => .left
  | ⟨18,_⟩ => .right        | ⟨19,_⟩ => .right
  | ⟨20,_⟩ => .ambidextrous
  -- Group 3 (Κ): mixed
  | ⟨21,_⟩ => .left         | ⟨22,_⟩ => .right
  | ⟨23,_⟩ => .right        | ⟨24,_⟩ => .ambidextrous
  | ⟨25,_⟩ => .ambidextrous | ⟨26,_⟩ => .ambidextrous
  | ⟨27,_⟩ => .ambidextrous
  -- Group 4 (Ω): mostly right
  | ⟨28,_⟩ => .left         | ⟨29,_⟩ => .left
  | ⟨30,_⟩ => .ambidextrous | ⟨31,_⟩ => .right
  | ⟨32,_⟩ => .right        | ⟨33,_⟩ => .right
  | ⟨34,_⟩ => .ambidextrous
  -- Group 5 (Σ): ambidextrous
  | ⟨35,_⟩ => .ambidextrous | ⟨36,_⟩ => .ambidextrous
  | ⟨37,_⟩ => .ambidextrous | ⟨38,_⟩ => .ambidextrous
  | ⟨39,_⟩ => .ambidextrous | ⟨40,_⟩ => .ambidextrous
  | ⟨41,_⟩ => .ambidextrous
  -- Group 6 (Π): mixed
  | ⟨42,_⟩ => .ambidextrous | ⟨43,_⟩ => .right
  | ⟨44,_⟩ => .right        | ⟨45,_⟩ => .ambidextrous
  | ⟨46,_⟩ => .ambidextrous | ⟨47,_⟩ => .left
  | ⟨48,_⟩ => .ambidextrous
  -- Group 7 (Ζ): undefined
  | ⟨49,_⟩ => .ambidextrous

-- =================================================================
-- §7. DIRECTION FROM EXPRESSION STRUCTURE
-- =================================================================

/-- The direction of an expression is determined by its dominant
    operation type:
    - Forward: mostly constructive operations (integration, summation,
      limits, expectation) → building mathematical objects
    - Reverse: mostly analytical operations (differentiation, division,
      negation, implication) → taking apart or measuring -/

def expressionDirection (tokens : List (Fin 50)) : Direction :=
  let chiralities := tokens.map tokenChiralityOfFin
  let leftCount := chiralities.filter (· == .left) |>.length
  let rightCount := chiralities.filter (· == .right) |>.length
  if leftCount ≥ rightCount then .forward else .reverse

-- =================================================================
-- §8. PHASE FROM TOKEN COMPOSITION
-- =================================================================

/-- The phase of an expression is computed from the weighted average
    of its token phases. Each token group has a base phase:
      Group 0 (Φ): 0°    Group 4 (Ω): 180°
      Group 1 (Λ): 45°   Group 5 (Σ): 225°
      Group 2 (Ρ): 90°   Group 6 (Π): 270°
      Group 3 (Κ): 135°  Group 7 (Ζ): 315°

    The expression phase is the weighted circular mean of constituent
    token phases, where weights are token frequencies. -/

def groupBasePhase (g : Fin 8) : ℕ :=
  match g.val with
  | 0 => 0 | 1 => 45 | 2 => 90 | 3 => 135
  | 4 => 180 | 5 => 225 | 6 => 270 | 7 => 315
  | _ => 0

def expressionPhase (tokens : List (Fin 50)) : Phase :=
  let groups := tokens.map tokenGroupOfFin
  let phases := groups.map groupBasePhase
  let weights := List.replicate phases.length 1  -- uniform weighting
  let avg := circularMean phases weights
  degreesToPhase avg
  where
    /-- Compute a weighted circular mean of phase angles.
        Uses a simplified linear-weighted average for computability. -/
    circularMean (phs : List ℕ) (wts : List ℕ) : ℕ :=
      if phs.isEmpty then 0
      else
        let totalWeight := List.sum wts
        if totalWeight = 0 then 0
        else List.sum (List.zipWith (λ p w => p * w) phs wts) / totalWeight % 360
    /-- Convert degrees to the nearest phase value. -/
    degreesToPhase : ℕ → Phase
      | 0 => .p0 | 45 => .p45 | 90 => .p90 | 135 => .p135
      | 180 => .p180 | 225 => .p225 | 270 => .p270 | 315 => .p315
      | d => if d < 22 then .p0 else if d < 67 then .p45
             else if d < 112 then .p90 else if d < 157 then .p135
             else if d < 202 then .p180 else if d < 247 then .p225
             else if d < 292 then .p270 else if d < 337 then .p315
             else .p0

-- =================================================================
-- §9. THE FULL 4D CLASSIFICATION
-- =================================================================

/-- Complete 4D classification of a mathematical expression.
    This replaces the simple (regime, subBasin) pair with a
    full geometric descriptor. -/
structure ChiralClassification where
  tokenAddress : Nat                    -- 50-bit token bitmask
  phase        : Phase                  -- circular mean of token phases
  chirality    : Chirality              -- dominant token chirality
  direction    : Direction              -- constructive vs analytical
  regime       : Regime                 -- beautiful/ugly/horrible
  consistent   : Bool                   -- satisfies all 8 constraints
  subBasin     : Nat                    -- Sidon sub-address
  pvgsParams   : Semantics.PVGS_DQ_Bridge.PVGSParams
  deriving Repr

/-- Compute the dominant chirality of a token list.
    Returns the chirality with the highest count, defaulting to
    ambidextrous for empty lists. -/
def dominantChirality (tokens : List (Fin 50)) : Chirality :=
  let chiralities := tokens.map tokenChiralityOfFin
  let leftCount := chiralities.filter (· == .left) |>.length
  let rightCount := chiralities.filter (· == .right) |>.length
  let ambCount := chiralities.filter (· == .ambidextrous) |>.length
  if leftCount ≥ rightCount ∧ leftCount ≥ ambCount then .left
  else if rightCount ≥ leftCount ∧ rightCount ≥ ambCount then .right
  else .ambidextrous

/-- Compute the dominant regime from the dominant group.
    Maps Hachimoji groups to regimes based on their character. -/
def dominantRegime (tokens : List (Fin 50)) : Regime :=
  let groups := tokens.map tokenGroupOfFin
  if groups.isEmpty then .beautiful
  else
    -- Regime depends on the most "extreme" group present
    let hasOmega := groups.any (λ g => g.val == 4)  -- paradox-prone
    let hasPi := groups.any (λ g => g.val == 6)     -- high-value conjectures
    let hasRho := groups.any (λ g => g.val == 2)    -- tight/constrained
    if hasOmega then .horrible
    else if hasPi then .ugly
    else if hasRho then .ugly
    else .beautiful

/-- Compute a Sidon-style sub-basin hash from a token address. -/
def sidonSubBasin (tokenAddress : Nat) : Nat :=
  -- Use the same hash function as in addressChaosBasin
  let tokens := addressTokens tokenAddress
  tokens.foldl (λ acc t => acc * 31 + t.val + 1) 0

/-- Convert a Q16_16.zero value for use in structure construction. -/
def q16_zero : Q16_16 := Q16_16.zero

/-- Convert an integer to Q16_16 by direct construction. -/
def q16_of_int (i : ℤ) : Q16_16 :=
  if h_min : i ≥ -2147483648 then
    if h_max : i ≤ 2147483647 then
      ⟨i, h_min, h_max⟩
    else
      ⟨2147483647, by norm_num, by norm_num⟩
  else
    ⟨-2147483648, by norm_num, by norm_num⟩

/-- Convert a token address to PVGS parameters, incorporating
    chirality and direction information. -/
def addressToPVGS (tokenAddress : Nat) (ch : Chirality) (dir : Direction) :
    Semantics.PVGS_DQ_Bridge.PVGSParams :=
  let baseParams :=
    { φ := q16_zero, μ_re := q16_zero, μ_im := q16_zero,
      ζ_mag := q16_zero, ζ_angle := q16_zero, k := 0, t := 0 }
  -- Modify based on chirality and direction
  match ch, dir with
  | .left, .forward =>
      { baseParams with μ_re := q16_of_int 1, k := 1 }
  | .right, .reverse =>
      { baseParams with μ_im := q16_of_int 1, k := 2 }
  | .ambidextrous, _ =>
      { baseParams with ζ_mag := q16_of_int 1 }
  | _, _ => baseParams

/-- Generate the full 4D classification from a token address.
    This is the ONE-FUNCTION API for chirality-aware encoding. -/

def classifyWithChirality (tokenAddress : Nat) : ChiralClassification :=
  let tokens := addressTokens tokenAddress
  let ph := expressionPhase tokens
  let ch := dominantChirality tokens
  let dir := expressionDirection tokens
  let reg := dominantRegime tokens
  let cons := isConsistent ph ch dir reg
  let sub := sidonSubBasin tokenAddress
  { tokenAddress := tokenAddress
  , phase := ph
  , chirality := ch
  , direction := dir
  , regime := reg
  , consistent := cons
  , subBasin := sub
  , pvgsParams := addressToPVGS tokenAddress ch dir
  }

-- =================================================================
-- §10. SCALING WITH CHIRALITY
-- =================================================================

/-- Without chirality: 2^50 token addresses × ~268M sub-basins
    ≈ 3 × 10^23 classified expressions.

    With chirality: each expression also has 144 possible 4D
    descriptors (though only ~60 are consistent). This gives
    2^50 × 60 × 268M ≈ 2 × 10^25 classified expressions.

    For context:
      - Atoms in the observable universe: ~10^80
      - 2 × 10^25: number of atoms in ~10^(-55) of the universe
      - But for mathematical expressions: this is effectively infinite.
        Every expression ever written, in every language, at every
        level of complexity, gets a unique (address, chirality, sub-basin)
        triple. -/

def scaledAddressSpace : Nat := 2^50 * 60 * (2^25)
-- ≈ 2 × 10^25

end ChiralitySpace
