// Minimal async render stub for profiling and I/O-decoupling experiments.
// Producer writes frames into a ring buffer; consumer simulates render thread.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>

#define RING_SIZE 16

typedef struct {
    uint64_t frame_id;
    double timestamp;
    double payload[8]; // small payload to simulate work
} frame_t;

static frame_t ring[RING_SIZE];
static volatile int prod_idx = 0;
static volatile int cons_idx = 0;
static pthread_mutex_t ring_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t ring_not_empty = PTHREAD_COND_INITIALIZER;
static int running = 1;

static double now_seconds(void) {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec + ts.tv_nsec * 1e-9;
}

void *producer(void *arg) {
    uint64_t id = 0;
    while (running) {
        // produce a frame
        frame_t f;
        f.frame_id = id++;
        f.timestamp = now_seconds();
        for (int i = 0; i < 8; ++i) f.payload[i] = f.timestamp * (i+1);

        pthread_mutex_lock(&ring_lock);
        int next = (prod_idx + 1) % RING_SIZE;
        if (next == cons_idx) {
            // ring full, drop oldest (move consumer ahead)
            cons_idx = (cons_idx + 1) % RING_SIZE;
        }
        ring[prod_idx] = f;
        prod_idx = next;
        pthread_cond_signal(&ring_not_empty);
        pthread_mutex_unlock(&ring_lock);

        // simulate variable production rate
        usleep(1000); // 1ms
    }
    return NULL;
}

void *consumer(void *arg) {
    (void)arg;
    while (running) {
        pthread_mutex_lock(&ring_lock);
        while (cons_idx == prod_idx && running) {
            pthread_cond_wait(&ring_not_empty, &ring_lock);
        }
        if (!running) { pthread_mutex_unlock(&ring_lock); break; }
        frame_t f = ring[(cons_idx) % RING_SIZE];
        cons_idx = (cons_idx + 1) % RING_SIZE;
        pthread_mutex_unlock(&ring_lock);

        // simulate render time
        double start = now_seconds();
        // pretend to rasterize payload (tiny compute)
        double acc = 0.0;
        for (int i = 0; i < 8; ++i) acc += f.payload[i] * 0.000001;
        (void)acc;
        double elapsed = now_seconds() - start;
        (void)elapsed;

        // optionally print a sample occasionally
        if ((f.frame_id & 0xFFF) == 0) {
            printf("render: frame=%llu ts=%.6f\n", (unsigned long long)f.frame_id, f.timestamp);
        }
    }
    return NULL;
}

int main(int argc, char **argv) {
    (void)argc; (void)argv;
    pthread_t prod, cons;
    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);

    // run for a few seconds
    sleep(5);
    running = 0;
    // wake consumer
    pthread_mutex_lock(&ring_lock);
    pthread_cond_signal(&ring_not_empty);
    pthread_mutex_unlock(&ring_lock);

    pthread_join(prod, NULL);
    pthread_join(cons, NULL);

    printf("async_render: finished\n");
    return 0;
}
