#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "bio/bio.h"
#include "../src/bio_kernel.h"

static void fill_input(uint8_t *p, size_t n) {
    for (size_t i = 0; i < n; ++i) {
        p[i] = (i < 32u) ? 0u : (uint8_t)(0x11u + (i & 0x03u));
    }
}

int main(void) {
    enum { N = 128 };
    uint8_t input[N];
    uint8_t scalar_state[N];
    uint8_t dispatch_state[N];
    bio_sparse_masks masks;
    uint64_t scalar_exec = 0;
    uint64_t scalar_base = 0;
    uint64_t dispatch_exec = 0;
    uint64_t dispatch_base = 0;

    memset(scalar_state, 0, sizeof(scalar_state));
    memset(dispatch_state, 0, sizeof(dispatch_state));
    fill_input(input, sizeof(input));

    bio_runtime_detect_features();
    bio_runtime_bind_kernels();

    bio_sparse_masks_reset(&masks, sizeof(input), 32u);
    bio_sparse_zpm_build(&masks, input, sizeof(input), 0u);
    if (masks.block_count != 4u || masks.skipped_blocks != 1u) {
        fprintf(stderr, "ZPM mask failed\n");
        return 1;
    }
    bio_sparse_omega_build(&masks, input, sizeof(input), 2u, 1u);
    bio_sparse_prune(&masks);
    if (masks.active_blocks == 0u || masks.active_blocks >= masks.block_count) {
        fprintf(stderr, "Omega route failed\n");
        return 1;
    }

    if (bio_pulse_int4_scalar(scalar_state, input, &masks, sizeof(input), 8u,
                              &scalar_exec, &scalar_base) != BIO_OK) {
        fprintf(stderr, "scalar pulse failed\n");
        return 1;
    }
    if (g_bio_kernels.pulse_int4(dispatch_state, input, &masks, sizeof(input), 8u,
                                 &dispatch_exec, &dispatch_base) != BIO_OK) {
        fprintf(stderr, "dispatch pulse failed\n");
        return 1;
    }
    if (memcmp(scalar_state, dispatch_state, sizeof(input)) != 0 ||
        scalar_exec != dispatch_exec || scalar_base != dispatch_base ||
        scalar_exec >= scalar_base) {
        fprintf(stderr, "kernel parity/accounting failed\n");
        return 1;
    }

    printf("bio-tests: sparse routing kernel ok variant=%s features=0x%x\n",
           g_bio_kernels.pulse_variant, bio_v1_cpu_features());
    return 0;
}
