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

#include "bio_bdl.h"
#include "bio_internal.h"
#include "bio_state.h"

static void copy_path(char *dst, const char *src) {
    if (src == NULL) {
        dst[0] = '\0';
        return;
    }
    snprintf(dst, BIO_BDST_PATH_BYTES, "%s", src);
}

uint64_t bio_state_checksum(const bio_state_table *state) {
    uint64_t x = 1469598103934665603ull;
    const uint8_t *p = (const uint8_t *)state;
    if (state == NULL) {
        return 0u;
    }
    for (size_t i = 0; i < sizeof(*state) - sizeof(state->checksum); ++i) {
        x ^= (uint64_t)p[i];
        x *= 1099511628211ull;
    }
    return x;
}

bio_v1_status bio_state_save(const char *state_path, const bio_state_table *state) {
    FILE *f = NULL;
    bio_state_table out;
    if (state_path == NULL || *state_path == '\0' || state == NULL) {
        return BIO_ERR_ARGS;
    }
    out = *state;
    out.checksum = bio_state_checksum(&out);
    f = fopen(state_path, "wb");
    if (f == NULL) {
        return BIO_ERR_IO;
    }
    if (fwrite(&out, sizeof(out), 1u, f) != 1u) {
        fclose(f);
        return BIO_ERR_IO;
    }
    fclose(f);
    return BIO_OK;
}

bio_v1_status bio_state_load(const char *state_path, bio_state_table *state) {
    FILE *f = NULL;
    bio_state_table in;
    uint64_t stored = 0;
    if (state_path == NULL || *state_path == '\0' || state == NULL) {
        return BIO_ERR_ARGS;
    }
    f = fopen(state_path, "rb");
    if (f == NULL) {
        return BIO_ERR_IO;
    }
    if (fread(&in, sizeof(in), 1u, f) != 1u) {
        fclose(f);
        return BIO_ERR_PARSE;
    }
    fclose(f);
    stored = in.checksum;
    in.checksum = 0u;
    if (in.magic != BIO_BDST_MAGIC || in.version != 1u ||
        bio_state_checksum(&in) != stored) {
        return BIO_ERR_PARSE;
    }
    in.checksum = stored;
    *state = in;
    return BIO_OK;
}

bio_v1_status bio_state_create(const char *gguf_path, const char *state_path,
                               const char *delta_path) {
    bio_gguf_model model;
    bio_state_table state;
    int8_t zero_delta[BIO_DELTA_LATTICE_BYTES];
    bio_v1_status rc = BIO_OK;
    if (gguf_path == NULL || state_path == NULL || delta_path == NULL ||
        *gguf_path == '\0' || *state_path == '\0' || *delta_path == '\0') {
        return BIO_ERR_ARGS;
    }
    rc = bio_gguf_open(gguf_path, &model);
    if (rc != BIO_OK) {
        return rc;
    }
    memset(&state, 0, sizeof(state));
    memset(zero_delta, 0, sizeof(zero_delta));
    state.magic = BIO_BDST_MAGIC;
    state.version = 1u;
    copy_path(state.gguf_path, gguf_path);
    copy_path(state.delta_path, delta_path);
    snprintf(state.architecture, sizeof(state.architecture), "%s",
             model.architecture[0] == '\0' ? "unknown" : model.architecture);
    state.context_length = model.context_length;
    state.embedding_length = model.embedding_length;
    state.block_count = model.block_count;
    state.feed_forward_length = model.feed_forward_length;
    state.attention_head_count = model.attention_head_count;
    state.attention_head_count_kv = model.attention_head_count_kv;
    state.vocab_size = model.vocab_size;
    state.tensor_count = model.registered_tensor_count;
    state.tokenizer_token_count = model.tokenizer_token_count;
    state.gguf_size = (uint64_t)model.mapping_size;
    rc = bio_state_save(state_path, &state);
    bio_gguf_close(&model);
    if (rc != BIO_OK) {
        return rc;
    }
    return bio_bdl_save(delta_path, zero_delta, sizeof(zero_delta), 0u);
}
