


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


#include "kvstore.h"
#include "kvs_rw_tools.h"
#include "mem_pool/mem_pool.h"
#include <arpa/inet.h>

// Key, Value --> 
// Modify 



kvs_hash_t global_hash;


//Connection 
// 'C' + 'o' + 'n'
static int _hash(const void *key, uint32_t key_len, int size) {
    if (!key || size <= 0) return -1;

    const uint8_t *p = (const uint8_t *)key;
    uint32_t sum = 0;
    for (uint32_t i = 0; i < key_len; i++) {
        sum += p[i];
    }
    return sum % size;
}

static int _key_equal(const hashnode_t *node, const void *key, uint32_t key_len) {
    if (!node || !key) return 0;
    if (!node->key) return 0;
    if (node->key_len != key_len) return 0;
    return memcmp(node->key, key, key_len) == 0;
}

static hashnode_t *_create_node(const void *key, uint32_t key_len,
                               const void *value, uint32_t value_len) {
    hashnode_t *node = (hashnode_t*)kvs_malloc(sizeof(hashnode_t));
    if (!node) return NULL;
    memset(node, 0, sizeof(*node));

    if (key_len > 0) {
        node->key = (uint8_t*)kvs_malloc(key_len);
        if (!node->key) { kvs_free(node); return NULL; }
        memcpy(node->key, key, key_len);
        node->key_len = key_len;
    }

    if (value_len > 0) {
        node->value = (uint8_t*)kvs_malloc(value_len);
        if (!node->value) {
            kvs_free(node->key);
            kvs_free(node);
            return NULL;
        }
        memcpy(node->value, value, value_len);
        node->value_len = value_len;
    } else {
        node->value = NULL;
        node->value_len = 0;
    }

    node->next = NULL;
    return node;
}


//
int kvs_hash_create(kvs_hash_t *hash) {
    if (!hash) return -1;

    hash->nodes = (hashnode_t**)kvs_malloc(sizeof(hashnode_t*) * MAX_TABLE_SIZE);
    if (!hash->nodes) return -1;

    memset(hash->nodes, 0, sizeof(hashnode_t*) * MAX_TABLE_SIZE);
    hash->max_slots = MAX_TABLE_SIZE;
    hash->count = 0;
    return 0;
}

// 
void kvs_hash_destroy(kvs_hash_t *hash) {
    if (!hash || !hash->nodes) return;

    for (int i = 0; i < hash->max_slots; i++) {
        hashnode_t *node = hash->nodes[i];
        while (node != NULL) {
            hashnode_t *tmp = node;
            node = node->next;

            if (tmp->key) kvs_free(tmp->key);
            if (tmp->value) kvs_free(tmp->value);
            kvs_free(tmp);
        }
        hash->nodes[i] = NULL;
    }

    kvs_free(hash->nodes);
    hash->nodes = NULL;
    hash->max_slots = 0;
    hash->count = 0;
}


// 5 + 2

// mp
/*
 * @return: <0 error; =0 success; >0 exist
 */
int kvs_hash_set_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, const void *value, uint32_t value_len) {
	if (!hash || !hash->nodes || !key || key_len == 0) return -1;

	int idx = _hash(key, key_len, MAX_TABLE_SIZE);
	if (idx < 0) return -1;

	hashnode_t *node = hash->nodes[idx];
	while (node != NULL) {
		if (_key_equal(node, key, key_len)) { // exist
			return 1;
		}
		node = node->next;
	}

	hashnode_t *new_node = _create_node(key, key_len, value, value_len);
	if (!new_node) return -2;

	new_node->next = hash->nodes[idx];
	hash->nodes[idx] = new_node;
	hash->count ++;

	return 0;
}

/*
 * get 返回：value 指针（由 hash 持有），并通过 out_value_len 返回长度
 */
void *kvs_hash_get_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, uint32_t *out_value_len) {
	if (!hash || !hash->nodes || !key || key_len == 0 || !out_value_len) return NULL;
	*out_value_len = 0;

	int idx = _hash(key, key_len, MAX_TABLE_SIZE);
	if (idx < 0) return NULL;

	hashnode_t *node = hash->nodes[idx];

	while (node != NULL) {

		if (_key_equal(node, key, key_len)) {
			*out_value_len = node->value_len;
			return node->value;
		}

		node = node->next;
	}

	return NULL;

}

/*
 * @return <0 error; =0 success; >0 no exist
 */
int kvs_hash_mod_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, const void *value, uint32_t value_len) {

	if (!hash || !hash->nodes || !key || key_len == 0 || !value) return -1;

	int idx = _hash(key, key_len, MAX_TABLE_SIZE);
	if (idx < 0) return -1;

	hashnode_t *node = hash->nodes[idx];

	while (node != NULL) {

		if (_key_equal(node, key, key_len)) {
			break;
		}

		node = node->next;
	}

	if (node == NULL) {
		return 1;
	}

	// node --> 
	if (node->value) kvs_free(node->value);
	node->value = NULL;
	node->value_len = 0;

	if (value_len > 0) {
        uint8_t *vcopy = (uint8_t*)kvs_malloc(value_len);
        if (!vcopy) return -2;
        memcpy(vcopy, value, value_len);
        node->value = vcopy;
        node->value_len = value_len;
    }	
	return 0;
}

int kvs_hash_count(kvs_hash_t *hash) {
	return hash->count;
}

/*
 * @return < 0, error;  =0,  success; >0, no exist
 */
int kvs_hash_del_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) {
	if (!hash || !key || key_len == 0) return -1;

	int idx = _hash(key, key_len, MAX_TABLE_SIZE);
	if (idx < 0) return -1;

	hashnode_t *head = hash->nodes[idx];
	if (head == NULL) return 1; // noexist

	// head node
	if (_key_equal(head, key, key_len)) {
		hashnode_t *tmp = head->next;
		hash->nodes[idx] = tmp;
		
		if (head->key) kvs_free(head->key);
		if (head->value) kvs_free(head->value);
		kvs_free(head);
		hash->count --;
		
		return 0;
	}

	hashnode_t *cur = head;
	while (cur->next != NULL) {
		if (_key_equal(cur->next, key, key_len)) break; // search node
		
		cur = cur->next;
	}

	if (cur->next == NULL) {
		
		return 1;
	}

	hashnode_t *tmp = cur->next;
	cur->next = tmp->next;
    if (tmp->key) kvs_free(tmp->key);
    if (tmp->value) kvs_free(tmp->value);
	kvs_free(tmp);
	
	hash->count --;

	return 0;
}

/*
 * @return 0 exist, 1 no exist
 */
int kvs_hash_exist_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) {
	uint32_t vlen = 0;
	void *value = kvs_hash_get_bin(hash, key, key_len, &vlen);
	return value ? 0 : 1;
}

// 0 suc, <0 error
int kvs_hash_save(kvs_hash_t *inst, const char* filename){
	if(!inst || !filename) return -1;
	FILE *fp = fopen(filename, "wb");
	if(!fp) return -2;


	for(int i = 0;i < inst->max_slots; ++ i){
		for (hashnode_t *n = inst->nodes[i]; n != NULL; n = n->next) {
			if (!n->key || n->key_len == 0) continue;
 			if (n->value_len > 0 && !n->value) { fclose(fp); return -3; }
		

			uint32_t klen = htonl((uint32_t)n->key_len);
			uint32_t vlen = htonl((uint32_t)n->value_len);

			if (kvs_write_file(fp, &klen, 4) < 0) { fclose(fp); return -4; }
			if (kvs_write_file(fp, &vlen, 4) < 0) { fclose(fp); return -4; }

			if (kvs_write_file(fp, n->key, n->key_len) < 0) { fclose(fp); return -4; }
			if (n->value_len > 0) {
				if (kvs_write_file(fp, n->value, n->value_len) < 0) { fclose(fp); return -4; }
			}
		}
	}

	fclose(fp);
	return 0;
}

int kvs_hash_load(kvs_hash_t *inst, const char* filename){
	if (!inst || !filename) return -1;
    if (!inst->nodes || inst->max_slots <= 0) return -1;

    FILE *fp = fopen(filename, "rb");
    if (!fp) return -2;

	while(1){
		uint32_t klen_n = 0, vlen_n = 0;

		if (kvs_read_file(fp, &klen_n, 4) < 0) { fclose(fp); return -3; }
		if (kvs_read_file(fp, &vlen_n, 4) < 0) { fclose(fp); return -3; }

		uint32_t klen = ntohl(klen_n);
        uint32_t vlen = ntohl(vlen_n);

		if (klen == 0) { fclose(fp); return -3; }

		uint8_t *keybuf = (uint8_t*)kvs_malloc((size_t)klen);
        if (!keybuf) { fclose(fp); return -4; }
        if (kvs_read_file(fp, keybuf, (size_t)klen) < 0) {
            kvs_free(keybuf);
            fclose(fp);
            return -3;
        }
		uint8_t *valbuf = NULL;
        if (vlen > 0) {
            valbuf = (uint8_t*)kvs_malloc((size_t)vlen);
            if (!valbuf) {
                kvs_free(keybuf);
                fclose(fp);
                return -4;
            }
            if (kvs_read_file(fp, valbuf, (size_t)vlen) < 0) {
                kvs_free(valbuf);
                kvs_free(keybuf);
                fclose(fp);
                return -3;
            }
        }

		int rc = kvs_hash_set_bin(inst, keybuf, klen, valbuf, vlen);
		kvs_free(keybuf);
        if (vlen > 0) kvs_free(valbuf);

		if (rc < 0) { // error
            fclose(fp);
            return -5;
        }
	}
	fclose(fp);
    return 0;
}