// ============================================================================
// face_demo_dialect.c — the minimal REFERENCE dialect: proves the universal
// operator (core/face_operator.c) against a second, non-C64, non-6502 guest.
// Zero OS/libc dependency (matches the core's own portability), compiles and
// runs standalone anywhere a C compiler exists -- the actual "closest to
// metal" proof that this architecture is dialect-agnostic, not just C64-
// shaped code wearing a universal-sounding name.
//
// This "guest" has no CPU to emulate: its own clock is a tick counter, its
// own console is a fixed-size buffer, its own input contract is "append at
// cursor, row 1". That's the whole machine -- deliberately trivial, so what
// gets proven is the OPERATOR (face_realize/tick/settle/checkpoint/genome/
// key), not this guest.
// ============================================================================
#include "../../core/face_node.h"

struct DemoSelf {
  unsigned char buf[FACE_SURFACE_SIZE];
  unsigned int  cursor;
  unsigned long tick;
};

static void demo_init(void* self)
{
  struct DemoSelf* s = (struct DemoSelf*)self;
  for(int i=0;i<FACE_SURFACE_SIZE;i++) s->buf[i] = ' ';
  const char* banner = "DEMO DIALECT READY.";
  for(int i=0; banner[i]; i++) s->buf[i] = (unsigned char)banner[i];
  s->cursor = FACE_SURFACE_COLS;   // typed input lands on row 1
  s->tick = 0;
}

static int demo_step(void* self, unsigned int quanta)
{
  struct DemoSelf* s = (struct DemoSelf*)self;
  // the guest's own endogenous clock: a bouncing marker on the last row --
  // observable proof that step() genuinely advances independent guest state,
  // the same contract the C64 dialect's real 6502 clock fulfills.
  s->tick += quanta;
  unsigned int pos = FACE_SURFACE_COLS*(FACE_SURFACE_ROWS-1);
  unsigned int span = FACE_SURFACE_COLS*2 - 2;
  unsigned int phase = (unsigned int)((s->tick / 1000) % span);
  unsigned int col = (phase < FACE_SURFACE_COLS) ? phase : (span - phase);
  for(unsigned int i=0;i<(unsigned)FACE_SURFACE_COLS;i++) s->buf[pos+i] = ' ';
  s->buf[pos+col] = '*';
  return 0;
}

static void demo_observe(void* self, unsigned char* surface, int cols, int rows)
{
  struct DemoSelf* s = (struct DemoSelf*)self;
  int n = cols*rows; if(n > FACE_SURFACE_SIZE) n = FACE_SURFACE_SIZE;
  for(int i=0;i<n;i++) surface[i] = s->buf[i];
}

static void demo_input(void* self, uint8_t key)
{
  struct DemoSelf* s = (struct DemoSelf*)self;
  if(s->cursor < (unsigned)(FACE_SURFACE_COLS*2)) s->buf[s->cursor++] = key;
}

static uint32_t demo_coord(void* self)
{
  return (uint32_t)((struct DemoSelf*)self)->tick;
}

// build a demo face -- no Memory, no ROM, no CPU. FaceBasis.mouse left null:
// this guest has no pointer contract, and that's fine -- mouse is optional.
static struct DemoSelf g_demo_self;
void face_bind_demo(struct FaceNode* f)
{
  g_demo_self.cursor = 0; g_demo_self.tick = 0;
  f->name = "demo";
  f->self = &g_demo_self;
  f->cols = FACE_SURFACE_COLS; f->rows = FACE_SURFACE_ROWS;
  f->basis.init    = demo_init;
  f->basis.step    = demo_step;
  f->basis.observe = demo_observe;
  f->basis.input   = demo_input;
  f->basis.mouse   = 0;
  f->basis.coord   = demo_coord;
}
