#include "pocketpy/common/serialize.h"

// >>> ord('🥕')
// 129365
// >>> ord('🍋')
// 127819

static uint32_t c11__checksum_32bit(const void* data, int size){
    const uint8_t* p = (const uint8_t*)data;
    uint32_t res = 0;
    for(int i = 0; i < size; i++){
        res = res * 31 + p[i];
    }
    return res;
}

void c11_serializer__ctor(c11_serializer* self, int16_t magic, int8_t major_ver, int8_t minor_ver){
    c11_vector__ctor(&self->data, 1);
    c11_serializer__write_i16(self, magic);
    c11_serializer__write_i8(self, major_ver);
    c11_serializer__write_i8(self, minor_ver);
}

void c11_serializer__dtor(c11_serializer* self){
    c11_vector__dtor(&self->data);
}

void c11_serializer__write_mark(c11_serializer *self, char mark) {
    c11_serializer__write_i8(self, (int8_t)mark);
}

void c11_serializer__write_cstr(c11_serializer *self, const char* cstr) {
    int len = (int)strlen(cstr);
    c11_serializer__write_bytes(self, cstr, len + 1);
}

void c11_serializer__write_bytes(c11_serializer* self, const void* data, int size){
    c11_vector__extend(&self->data, data, size);
}

void* c11_serializer__submit(c11_serializer* self, int* size){
    uint32_t checksum = c11__checksum_32bit(self->data.data, self->data.length);
    c11_serializer__write_bytes(self, &checksum, sizeof(uint32_t));
    return c11_vector__submit(&self->data, size);
}

void c11_deserializer__ctor(c11_deserializer* self, const void* data, int size){
    self->data = (const uint8_t*)data;
    self->size = size;
    self->index = 0;
    self->error_msg[0] = '\0';
}

void c11_deserializer__dtor(c11_deserializer* self){
    // nothing to do
}

bool c11_deserializer__error(c11_deserializer* self, const char* msg){
    snprintf(self->error_msg, sizeof(self->error_msg), "%s", msg);
    return false;
}

void c11_deserializer__consume_mark(c11_deserializer* self, char expected) {
    int8_t mark = c11_deserializer__read_i8(self);
    if (mark != (int8_t)expected) {
        c11__abort("internal error: deserialize mark mismatch: expected %c but got %c", expected, (char)mark);
    }
}

bool c11_deserializer__check_header(c11_deserializer* self, int16_t magic, int8_t major_ver, int8_t minor_ver_min){
    if(self->size < 8){
        return c11_deserializer__error(self, "bad header: size < 8");
    }
    // read 16bit magic
    int16_t file_magic = c11_deserializer__read_i16(self);
    if(file_magic != magic){
        return c11_deserializer__error(self, "bad header: magic mismatch");
    }
    // read 16bit version
    self->major_ver = c11_deserializer__read_i8(self);
    self->minor_ver = c11_deserializer__read_i8(self);

    // check checksum
    uint32_t checksum;
    memcpy(&checksum, self->data + self->size - 4, sizeof(uint32_t));
    uint32_t actual_checksum = c11__checksum_32bit(self->data, self->size - 4);
    if(checksum != actual_checksum){
        return c11_deserializer__error(self, "bad header: checksum mismatch");
    }
    // check version
    if(self->major_ver != major_ver){
        return c11_deserializer__error(self, "bad header: major version mismatch");
    }
    if(self->minor_ver < minor_ver_min){
        // file_ver: 1.1, require_ver: 1.0 => ok
        // file_ver: 1.1, require_ver: 1.1 => ok
        // file_ver: 1.1, require_ver: 1.2 => error
        return c11_deserializer__error(self, "bad header: minor version mismatch");
    }
    return true;
}

const char* c11_deserializer__read_cstr(c11_deserializer* self){
    const char* p = (const char*)(self->data + self->index);
    self->index += (strlen(p) + 1);
    return p;
}

void* c11_deserializer__read_bytes(c11_deserializer* self, int size){
    void* p = (void*)(self->data + self->index);
    self->index += size;
    return p;
}