// ============================================================================
// HDGL SUBSTRATE CORE  —  faithful to OS64-faces (hdgl_faces.img)
//
// The substrate IS the machine. It ticks continuously: each tick advances tau,
// RE-SETTLES Omega = Fix(T) = phi by iterating T(X)=1+1/X (nothing stored that
// can be derived), and steps every face one quantum. Faces are projections of
// the substrate, each with phi-fold-derived private tape, interleaved one unit
// per tick. The C64 is ONE face among many, not a hosted guest.
//
// This mirrors run_substrate + orbit_loop + face_step_all from stage2_faces.asm.
// ============================================================================
#include <lib/stdint.h>
#include <c64/substrate.h>

namespace hdgl {

// ── the living substrate state (all DERIVED each tick, not stored constants) ──
Substrate g_sub = {
  /*tau*/    0,
  /*S*/      2.0L,      // seed; T iterates it to phi
  /*T*/      0.0L,
  /*Omega*/  0.0L,
  /*Psi*/    0.0L,
  /*Lambda*/ 0,
  /*Nphi*/   1,
  /*genome*/ 0,
  /*session*/0
};

// T(X) = 1 + 1/X   — the single axiom. phi is its fixed point.
static inline long double T_of(long double x){ return 1.0L + 1.0L / x; }

// phi_fold32 — the privacy/entropy fold (multiplicative hash in the phi spirit).
// Used for face privacy tokens: phi_fold(genome ^ session ^ face_id).
uint32_t phi_fold(uint32_t x){
  // 0x9E3779B9 = round(2^32 / phi) — the golden-ratio constant, DERIVED from phi.
  x ^= x >> 16; x *= 0x9E3779B9u;
  x ^= x >> 13; x *= 0x85EBCA77u;
  x ^= x >> 16;
  return x;
}

// Re-settle Omega = Fix(T) by iterating T until |xb-xa| < eps. Counts Lambda.
// This is the heart: phi is NOT stored — it is RE-FOUND every tick from S.
static void settle(){
  const long double eps = 1e-17L;
  g_sub.T = T_of(g_sub.S);
  long double xa = g_sub.T, xb;
  g_sub.Lambda = 0;
  for(int i=0; i<300; i++){
    xb = T_of(xa);
    long double d = xb - xa; if(d < 0) d = -d;
    if(d < eps){ xa = xb; break; }
    xa = xb;
    g_sub.Lambda++;
  }
  g_sub.Omega = xa;                 // = phi = 1.6180339887...
  g_sub.Psi   = -1.0L / g_sub.Omega;
  g_sub.Nphi  = (g_sub.tau & 1) ? -1 : +1;   // trinary (-1)^tau
}

void substrate_init(uint32_t session_coord){
  g_sub.tau = 0;
  g_sub.S = 2.0L;
  g_sub.session = session_coord;
  // settle_genome: fold the session so the genome differs each boot but is
  // DERIVED, never stored as a magic constant.
  g_sub.genome = phi_fold(0x5D5EED ^ session_coord);
  settle();
}

// One substrate tick: advance tau, keep S alive (Delta-perturbed but Fix(T)
// is invariant), re-settle Omega. The substrate is alive iff Delta != 0, yet
// Omega is the SAME phi every tick — that is what "fixed point" means.
void substrate_tick(){
  g_sub.tau++;
  // Delta perturbation: nudge S away from the fixed point so the settle is
  // real work each tick (alive), not a cached constant. Any nonzero seed
  // converges to phi, proving Omega = Fix(T) regardless of Delta.
  g_sub.S = 2.0L + (long double)((g_sub.tau * 2654435761u) & 0xFF) / 4096.0L;
  settle();
}

// ── FACE TABLE ──────────────────────────────────────────────────────────
Face g_faces[HDGL_MAX_FACES];
int  g_face_count = 0;

uint32_t face_register(void* self, face_step_fn step){
  if(g_face_count >= HDGL_MAX_FACES) return (uint32_t)-1;
  uint32_t id = (uint32_t)g_face_count;
  Face& f = g_faces[g_face_count++];
  f.active = 1;
  f.id = id;
  // privacy token: phi_fold(genome ^ session ^ id) — derived, per-boot, disjoint
  f.priv_token = phi_fold(g_sub.genome ^ g_sub.session ^ id);
  f.self = self;
  f.step = step;
  return id;
}

// step every active face ONE quantum this tick — genuinely interleaved,
// exactly like the reference face_step_all called from orbit_loop.
void face_step_all(){
  for(int i=0; i<g_face_count; i++){
    Face& f = g_faces[i];
    if(f.active && f.step) f.step(f.self, f.id, f.priv_token);
  }
}

} // namespace hdgl
