/*
 * api.c
 *
 *  Created on: Apr 24, 2022
 *      Author: mateusz
 *
 *
 *      19 maja, Krszystof Binek, miedy 12 a 13
 */

#include <api/api_content.h>
#include "etc/api_configuration.h"

#include "http_client/http_client.h"

#include "stdint.h"
#include "aes.h"

/**
 * Buffers for generating JSON and URL
 */
#define API_BUFFER_LN	640
char api_buffer[API_BUFFER_LN];
#define URL_BUFFER_LN	96
char api_url_buffer[URL_BUFFER_LN];

/**
 * Index to move around a buffer with request body
 */
uint32_t api_buffer_idx = 0;

/**
 * Value returned from http client
 */
uint8_t api_retval = 0xFF;

/**
 * Cycle counter to control the frequency of api calls
 */
int8_t api_cycle_counter = 0;

/**
 * Message authentication code encrypted by AES128 and converted to hex string
 */
char api_mac[33];

/**
 * Buffer to perform encryption of the MAC
 */
uint8_t api_aes_mac_buffer[16];

struct AES_ctx api_aes_context;

const uint8_t api_shared_secret[] = API_SHARED_SECRET;

const uint8_t api_iv[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

/**
 * This is used to retrigger specific api communication in case of any request
 * appears on the same call to `api_pooler` function. For code simplicity only one
 * API request is possible in the single 'api_pooler' cycle
 */
#define API_TRIGGER_STATUS			(1 << 1)
#define API_TRIGGER_MEASUREMENTS	(1 << 2)
int8_t api_retrigger_api_call = 0;

/**
 * Pointers to base url and station name (stored within flash)
 */
const char * api_base_url;
const char * api_station_name;

typedef enum api_endpoint{

	PARAMETEO_STATUS,
	PARAMETEO_WX
} api_endpoint_t;

#define	LN	api_buffer_idx
#define OUT api_buffer

static void api_construct_url_status(api_endpoint_t endpoint) {

	if (api_base_url != 0x00 && api_station_name != 0x00) {
		memset(api_url_buffer, 0x00, URL_BUFFER_LN);

		switch (endpoint) {
		case PARAMETEO_STATUS:
			snprintf(api_url_buffer, URL_BUFFER_LN - 1, "%s/parameteo/%s/status/v1", api_base_url, api_station_name);
			break;
		case PARAMETEO_WX:
			snprintf(api_url_buffer, URL_BUFFER_LN - 1, "%s/parameteo/%s/measurements/v1", api_base_url, api_station_name);
			break;
		}
	}

}

static void api_callback(uint16_t http_code, char * content, uint16_t content_lenght) {

	http_client_close();


}

void api_init(const char * api_base, const char * station_name) {
	api_base_url = api_base;
	api_station_name = station_name;
	AES_init_ctx_iv(&api_aes_context, api_shared_secret, api_iv);
	memset(api_mac, 0x00, 33);
	memset(api_mac, '0', 32);
}


void api_calculate_mac(void) {

	// iterators used during conversion to hex string after encryption
	int i = 0, j = 0;

	memset(api_aes_mac_buffer, 0x00, 16);
	memset(api_mac, 0x00, 33);

	api_aes_mac_buffer[0] = (uint8_t)((master_time & 0xFF));
	api_aes_mac_buffer[1] = (uint8_t)((master_time & 0xFF00) >> 8);
	api_aes_mac_buffer[2] = (uint8_t)((master_time & 0xFF0000) >> 16);
	api_aes_mac_buffer[3] = (uint8_t)((master_time & 0xFF000000) >> 24);
	api_aes_mac_buffer[4] = (uint8_t)((rte_main_average_battery_voltage & 0xFF));
	api_aes_mac_buffer[5] = (uint8_t)((rte_main_average_battery_voltage & 0xFF00) >> 8);
	api_aes_mac_buffer[6] = (uint8_t)((rte_wx_average_winddirection & 0xFF));
	api_aes_mac_buffer[7] = (uint8_t)((rte_wx_average_winddirection & 0xFF00) >> 8);
	api_aes_mac_buffer[8] = (uint8_t)((rte_wx_average_windspeed & 0xFF));
	api_aes_mac_buffer[9] = (uint8_t)((rte_wx_average_windspeed & 0xFF00) >> 8);
	api_aes_mac_buffer[10] = (uint8_t)((rte_wx_max_windspeed & 0xFF));
	api_aes_mac_buffer[11] = (uint8_t)((rte_wx_max_windspeed & 0xFF00) >> 8);
	api_aes_mac_buffer[12] = (uint8_t)((rte_wx_pm2_5 & 0xFF));
	api_aes_mac_buffer[13] = (uint8_t)((rte_wx_pm2_5 & 0xFF00) >> 8);
	api_aes_mac_buffer[14] = (uint8_t)((rte_wx_temperature_average_dallas & 0xFF));
	api_aes_mac_buffer[15] = (uint8_t)((rte_wx_temperature_average_dallas & 0xFF00) >> 8);

	AES_CBC_encrypt_buffer(&api_aes_context, api_aes_mac_buffer, 16);

	for (i = 0; i < 16; i++) {
		snprintf(api_mac + j, 3, "%02X", api_aes_mac_buffer[i]);
		j += 2;
	}

}

void api_send_json_status(void) {
	BEGIN
	PRINT_ALL_STATUS
	END

	if (api_buffer_idx < API_BUFFER_LN) {
		api_construct_url_status(PARAMETEO_STATUS);

		api_retval = http_client_async_post(api_url_buffer, strlen(api_url_buffer), OUT, strlen(OUT), 0, api_callback);
	}
}

void api_send_json_measuremenets(void) {
	BEGIN
	PRINT_ALL_MEASUREMENTS
	END

	if (api_buffer_idx < API_BUFFER_LN) {
		api_construct_url_status(PARAMETEO_WX);

		api_retval = http_client_async_post(api_url_buffer, strlen(api_url_buffer), OUT, strlen(OUT), 0, api_callback);
	}
}


