// ============================================================================
// face_operator.c — the universal face operator. Dialect-free by
// construction: this file only ever touches FaceNode/FaceCheckpoint fields,
// face_phi_hash, and the real phi-lattice substrate (../substrate/
// phi_lattice.asm). It has been exercised against exactly one dialect (C64,
// see ../dialects/c64/) but nothing here depends on that dialect -- verify
// this claim yourself by grep: no "c64"/"6502"/"KERNAL" appears below.
//
// face_realize / face_tick / face_key are basis-agnostic: they observe the
// guest into the projection surface and never drive it. A new dialect fills
// FaceBasis's callbacks with a different machine -- this file is unchanged.
// ============================================================================
#include "face_node.h"
#include "../substrate/phi_lattice.h"

// ── phi-hash: φ-fold identity, no stored constants (Ω = Fix(T)) ──
uint64_t face_phi_hash(const char* name)
{
  // φ as a rational fold: multiply-accumulate by the Fibonacci-adjacent ratio.
  // (Derived, not stored: 0x9E3779B97F4A7C15 is 2^64 / φ, the golden hash.)
  uint64_t h = 0;
  for(const char* p = name; p && *p; ++p)
    h = (h ^ (uint8_t)*p) * 0x9E3779B97F4A7C15ULL + 1;
  return h;
}

// ── the universal operator ──────────────────────────────────────────────────

void face_realize(struct FaceNode* f)
{
  if(!f) return;
  f->id    = face_phi_hash(f->name);
  f->cols  = f->cols ? f->cols : FACE_SURFACE_COLS;
  f->rows  = f->rows ? f->rows : FACE_SURFACE_ROWS;
  for(int i=0;i<FACE_SURFACE_SIZE;i++) f->surface[i] = ' ';
  f->settle_lock = 0;
  f->checkpoint_count = 0;
  f->lattice_tick = 0;
  for(int i=0;i<9;i++) f->genome[i] = 0;
  // seed the lattice from the face's own φ-hash identity -- derived, not a
  // stored table (matches hdgl_kernel.hdgl's phi_lattice glyph: "seed_func
  // = prismatic_recursion", here expressed as seed_func = phi_hash(id, i)).
  for(int i=0;i<PHI_LATTICE_SLOTS;i++){
    uint64_t h = (f->id ^ (uint64_t)i) * 0x9E3779B97F4A7C15ULL + 1;
    uint32_t v = (uint32_t)(h >> 32);
    f->lattice[i] = (v < 0x100) ? 0x100 : v;  // respect GUZ floor on seed too
  }
  if(f->basis.init) f->basis.init(f->self);   // Fix(project): realize hardware
  f->state  = FACE_READY;
  f->active = 1;
}

// genome(): dna_encode — the face's Fix-point identity as {A,C,G,T}. 2 bits per
// base (same scheme as water_glyphs2/phi_pool_kuramoto.c's genome_fp decode),
// folded from the observed surface via the project's own φ-hash primitive.
void face_genome(struct FaceNode* f)
{
  if(!f) return;
  static const char base[4] = {'A','C','G','T'};
  uint64_t h = f->id;
  for(int i=0;i<FACE_SURFACE_SIZE;i++)
    h = (h ^ f->surface[i]) * 0x9E3779B97F4A7C15ULL + 1;
  for(int i=0;i<8;i++)
    f->genome[i] = base[(h >> (i*2)) & 0x3];
  f->genome[8] = 0;
}

// settle(): the REAL substrate. Folds the observed surface (Δ, endogenous --
// the substrate never drives the guest) into the lattice's tick, runs one
// real phi-lattice recursion (substrate/phi_lattice.asm -- the same asm
// Router64 boots and reports LOCK/UNLOCK with), and reads consensus.
void face_settle(struct FaceNode* f)
{
  if(!f) return;
  uint64_t fold = 0;
  for(int i=0;i<FACE_SETTLE_WINDOW;i++)
    fold = (fold ^ f->surface[i]) * 0x9E3779B97F4A7C15ULL + 1;
  f->lattice_tick ^= fold;                    // guest's own Δ drives the tick
  phi_lattice_tick(f->lattice, &f->lattice_tick);        // Ω(n+1)=T(Ω(n)), asm
  int was_locked = f->settle_lock;
  f->settle_lock = phi_lattice_consensus(f->lattice);    // real consensus, asm
  if(f->settle_lock && !was_locked) face_checkpoint(f);   // checkpoint the LOCK edge
}


// checkpoint(): onion-shell layered snapshot (core/dna/combined φ-hash),
// pushed into the fixed-size ring — no malloc, reversible, observation-only.
void face_checkpoint(struct FaceNode* f)
{
  if(!f) return;
  uint64_t core = f->id;
  for(int i=0;i<FACE_SURFACE_SIZE;i++) core = (core ^ f->surface[i]) * 0x9E3779B97F4A7C15ULL + 1;
  uint64_t dna = f->id;
  for(int i=0;i<8 && f->genome[i];i++) dna = (dna ^ (uint8_t)f->genome[i]) * 0x9E3779B97F4A7C15ULL + 1;
  struct FaceCheckpoint* cp = &f->checkpoints[f->checkpoint_count % FACE_CHECKPOINT_RING];
  cp->op_id        = f->checkpoint_count;
  cp->shell_core     = core;
  cp->shell_dna       = dna;
  cp->shell_combined  = (core ^ dna) * 0x9E3779B97F4A7C15ULL + 1;
  f->checkpoint_count++;
}

void face_tick(struct FaceNode* f)
{
  if(!f || !f->active) return;
  // step the guest against the projected hardware (endogenous Δ)
  if(f->basis.step) f->basis.step(f->self, 200000);
  // OBSERVE the guest's own screen into the projection surface (read-only)
  if(f->basis.observe) f->basis.observe(f->self, f->surface, f->cols, f->rows);
  face_genome(f);   // genome = dna_encode of Fix(project)
  face_settle(f);    // settle = breathing_cycle (checkpoints on the LOCK edge)
  if(f->state < FACE_EXECUTED) f->state = FACE_EXECUTED;
}

// Low-latency variants: step a small batch (so input can be polled between
// batches), and observe separately (once per frame). Same operator, finer grain.
void face_tick_steps(struct FaceNode* f, unsigned int quanta)
{
  if(!f || !f->active) return;
  if(f->basis.step) f->basis.step(f->self, quanta);
  if(f->state < FACE_EXECUTED) f->state = FACE_EXECUTED;
}

void face_tick_observe(struct FaceNode* f)
{
  if(!f || !f->active) return;
  if(f->basis.observe) f->basis.observe(f->self, f->surface, f->cols, f->rows);
  face_genome(f);
  face_settle(f);
}

void face_key(struct FaceNode* f, uint8_t key)
{
  if(!f || !f->active) return;
  if(f->basis.input) f->basis.input(f->self, key);  // authentic input path
}

void face_mouse(struct FaceNode* f, int8_t dx, int8_t dy, uint8_t buttons)
{
  if(!f || !f->active) return;
  if(f->basis.mouse) f->basis.mouse(f->self, dx, dy, buttons);  // authentic path
}
