#include "foc/mc_error.h"
#include "libs/logger.h"
#include "app/nv_storage.h"
#include "libs/crc16.h"
#include "libs/utils.h"

static u8 page_buff[one_page_size];
static u8 page_buff_runtime[one_page_size];
static err_nv_t *_e_nv = NULL;
static runtime_nv_t *_r_nv = NULL;
static bool _w_pending = false;
static bool _w_pending_rt = false;
#define ERR_MAX_SIZE 255
#define RUNTIME_MAX_SIZE 50

void mc_err_block_init(int rst_event) {
	_e_nv = (err_nv_t *)page_buff;
	nv_read_crit_errblock(page_buff, one_page_size);
	u16 crc16 = crc16_get((u8 *)_e_nv->node, one_page_size - sizeof(err_nv_t));
	if (crc16 != _e_nv->crc) {
		memset(page_buff, 0, one_page_size);
		_e_nv->crc = crc16_get((u8 *)_e_nv->node, one_page_size - sizeof(err_nv_t));
		nv_write_crit_errblock(page_buff, one_page_size);
		sys_debug("mc crc\n");
	}

	_r_nv = (runtime_nv_t *)page_buff_runtime;
	nv_read_runtime_block(page_buff_runtime, one_page_size);
	crc16 = crc16_get((u8 *)_r_nv->node, one_page_size - sizeof(runtime_nv_t));
	if (crc16 != _r_nv->crc) {
		memset(page_buff_runtime, 0, one_page_size);
		_r_nv->crc = crc16_get((u8 *)_r_nv->node, one_page_size - sizeof(runtime_nv_t));
		nv_write_runtime_block(page_buff_runtime, one_page_size);
		sys_debug("mc rt crc\n");
	}
	u32 rst_src = get_mcu_reset_source();
	mc_crit_err_add(rst_event, (rst_src&0xFFFF), (rst_src>>16&0xFFFF));
	sys_debug("mc err size %d -%d\n", sizeof(err_node_t) * ERR_MAX_SIZE + sizeof(err_nv_t), sizeof(runtime_node_t) * RUNTIME_MAX_SIZE+ sizeof(runtime_nv_t));
}

void mc_crit_err_add(u8 code, s16 value1, s16 value2) {
	err_node_t *node = _e_nv->node;
	node = node + _e_nv->tail;
	node->idx = _e_nv->tail;
	node->err_code = code;
	node->value1 = value1;
	node->value2 = value2;
	_e_nv->tail = (_e_nv->tail + 1) % ERR_MAX_SIZE; //next add index
	_e_nv->count++;
	if (_e_nv->count > ERR_MAX_SIZE) {
		_e_nv->count = ERR_MAX_SIZE;
	}
	_w_pending = true;
}

void mc_crit_err_add_s16(u8 code, s16 value) {
	mc_crit_err_add(code, value, -1);
}


void mc_err_runtime_add(runtime_node_t *rt) {
	runtime_node_t *node = _r_nv->node;
	node = node + _r_nv->tail;
	memcpy(node, rt, sizeof(runtime_node_t));
	node->idx = _r_nv->tail;
	_r_nv->tail = (_r_nv->tail + 1) % RUNTIME_MAX_SIZE; //next add index
	_r_nv->count++;
	if (_r_nv->count > RUNTIME_MAX_SIZE) {
		_r_nv->count = RUNTIME_MAX_SIZE;
	}
	_w_pending_rt = true;
}


void mc_err_block_save(void) {
	if (_w_pending) {
		_e_nv->crc = crc16_get((u8 *)_e_nv->node, one_page_size - sizeof(err_nv_t));
		nv_write_crit_errblock(page_buff, one_page_size);
		_w_pending = false;
	}
	if (_w_pending_rt) {
		_r_nv->crc = crc16_get((u8 *)_r_nv->node, one_page_size - sizeof(runtime_nv_t));
		nv_write_runtime_block(page_buff_runtime, one_page_size);
		_w_pending_rt = false;
	}
}

int mc_crit_err_get(s16 offset, u8 *buff, int len) {
	int count = (len - 1) / sizeof(err_node_t);
	int index = offset;
	u8 *p_remain = buff++;
	if (_e_nv->count == ERR_MAX_SIZE) {
		index = (index + _e_nv->tail) % ERR_MAX_SIZE;
	}
	int remain = (offset > _e_nv->count)?0:(_e_nv->count - offset);
	count = min(count, remain);
	err_node_t *node = _e_nv->node;
	len = 0;
	*p_remain = count;
	len ++;
	while (count--) {
		memcpy(buff, (u8 *)(node + index), sizeof(err_node_t));
		buff += sizeof(err_node_t);
		index = (index + 1) % ERR_MAX_SIZE;
		len += sizeof(err_node_t);
	}

	return len;

}


int mc_err_runtime_get(s16 offset, u8 *buff, int len) {
	int count = (len - 1) / sizeof(runtime_node_t);
	int index = offset;
	u8 *p_remain = buff++;
	if (_r_nv->count == RUNTIME_MAX_SIZE) {
		index = (index + _r_nv->tail) % RUNTIME_MAX_SIZE;
	}
	int remain = (offset > _r_nv->count)?0:(_r_nv->count - offset);
	count = min(count, remain);
	runtime_node_t *node = _r_nv->node;
	len = 0;
	*p_remain = count;
	len ++;
	while (count--) {
		memcpy(buff, (u8 *)(node + index), sizeof(runtime_node_t));
		buff += sizeof(runtime_node_t);
		index = (index + 1) % RUNTIME_MAX_SIZE;
		len += sizeof(runtime_node_t);
	}

	return len;
}


void mc_err_code_log(void) {
	if (_e_nv->count > 0) {
		sys_debug("mc err count %d, tail %d\n", _e_nv->count, _e_nv->tail);
	}
	if (_r_nv->count > 0) {
		sys_debug("mc rt count %d, tail %d\n", _r_nv->count, _r_nv->tail);
	}
}
