/**
 *****************************************************************************************
 *	@file etn_mesh_fota_upd_cli.c
 *
 *	@brief eaton ble mesh fota firmware update client model source file
 *
 *	@details this custom model from eaton, used for firmware update client model
 *
 *	@version C Style Guide Version 1.0
 *
 *	@copyright 2022 Eaton Corporation. All Rights Reserved.
 *
 *****************************************************************************************
 */

/*
 *****************************************************************************************
 *		Headers
 *****************************************************************************************
 */
#include <zephyr.h>
#include <etn_mesh_fota.h>
#include <etn_mesh_fota_upd.h>
#include <etn_mesh_fota_upd_cli.h>
#include <logging/log.h>

LOG_MODULE_REGISTER( etn_upd_cli, LOG_LEVEL_DBG );

/*
 *****************************************************************************************
 *		Defines
 *****************************************************************************************
 */


/*
 *****************************************************************************************
 *		Constants
 *****************************************************************************************
 */

/*
 *****************************************************************************************
 *		Variables
 *****************************************************************************************PLAT
 */

/*
 *****************************************************************************************
 *		Typedefs
 *****************************************************************************************
 */


/*
 *****************************************************************************************
 * See header file for function definition.
 *****************************************************************************************
 */
/*
 *****************************************************************************************
 *		handlers for eaton mesh fota firmware update client
 *****************************************************************************************
 */

static struct etn_fota_error   	upd_cli_err_report;

static uint8_t image_progress_value = 50;	
static enum fota_upd_srv_state state;

static void encode_state( struct net_buf_simple* buf,
						  enum fota_upd_srv_state updatesrv_state )
{
	bt_mesh_model_msg_init( buf, BT_MESH_ETN_FOTA_UPD_SRV_STATE_GET_OP );
	net_buf_simple_add_u8( buf, updatesrv_state );
}

static int bt_mesh_fota_upd_cli_server_update_handler( struct bt_mesh_model* model )
{
	struct bt_mesh_etn_fota_upd_cli *updcli = model->user_data;

	/* Continue publishing current state. */
	encode_state( model->pub->msg, state );

	return ( 0 );
}

static int bt_mesh_fota_upd_cli_init( struct bt_mesh_model* model )
{
	struct bt_mesh_etn_fota_upd_cli *updcli = model->user_data;

	updcli->model = model;

	net_buf_simple_init_with_data( &updcli->pub_msg, updcli->buf,
								   sizeof( updcli->buf ) );
	updcli->pub.msg = &updcli->pub_msg;
	updcli->pub.update = bt_mesh_fota_upd_cli_server_update_handler;

	return ( 0 );
}

static int bt_mesh_fota_upd_cli_start( struct bt_mesh_model* model )
{
	struct bt_mesh_etn_fota_upd_cli *updcli = model->user_data;

	state = UPD_SRV_FW_UPDATE_AVLBL;

	if ( updcli->handlers->start )
	{
		updcli->handlers->start( updcli );
	}

	return ( 0 );
}

static void bt_mesh_fota_upd_cli_reset( struct bt_mesh_model* model )
{
	state = UPD_SRV_FW_UPDATE_AVLBL;
	struct bt_mesh_etn_fota_upd_cli *updcli = model->user_data;
	updcli->model = model;

	net_buf_simple_init_with_data( &updcli->pub_msg, updcli->buf,
								   sizeof( updcli->buf ) );
	updcli->pub.msg = &updcli->pub_msg;
}

/**
 * @brief	BLE-Mesh firmware update server model, instantiation callbacks registration
 */
const struct bt_mesh_model_cb _bt_mesh_etn_fota_upd_cli_cb = {
	.init = bt_mesh_fota_upd_cli_init,
	.start = bt_mesh_fota_upd_cli_start,
	.reset = bt_mesh_fota_upd_cli_reset,
};

int fota_upd_cli_extract_progress_get(struct net_buf_simple *buf, uint8_t *value )
{
	int status=0;
	int len=0;

	len = buf->len;

	if(len == 1 )
	{
		*value = net_buf_simple_pull_u8(buf);
		status = 0;
	}
	else
	{
		LOG_ERR( "Err in update progress get opcode number of bytes received, bytes len:%d",len );
		status = -1;
	}

	return status;
}

int fota_upd_cli_extract_server_state_get(struct net_buf_simple *buf, uint8_t *value )
{
	int status=0;
	int len=0;

	len = buf->len;

	if(len == 1 )
	{
		*value = net_buf_simple_pull_u8(buf);
		status = 0;
	}
	else
	{
		LOG_ERR( "Err in update server state get opcode number of bytes received, bytes len:%d",len );
		status = -1;
	}

	return status;
}

static int opcode_handler_fota_upd_cli_progress_get( struct bt_mesh_model* model, struct bt_mesh_msg_ctx* ctx, struct net_buf_simple* buf )
{
	struct bt_mesh_etn_fota_upd_cli *updcli = model->user_data;
	int parse_status=0;

	parse_status = fota_upd_cli_extract_progress_get(buf, &image_progress_value);

	if(parse_status == 0)
	{
		if ( updcli->handlers->image_progress_get )
		{
			updcli->handlers->image_progress_get( &image_progress_value );
		}
	}
	else
	{
		LOG_DBG( "data parse error" );
		upd_cli_err_report.opcode = BT_MESH_ETN_FOTA_UPD_PROGRESS_GET_OP;
		upd_cli_err_report.err_code = FOTA_ERROR_DATA_PARSE;
		
		if (updcli->handlers->error_reporting)
		{
			updcli->handlers->error_reporting(updcli, ctx, &upd_cli_err_report);
		}
	}
	
	return ( 0 );
}

static int opcode_handler_fota_upd_cli_server_state_get( struct bt_mesh_model* model, struct bt_mesh_msg_ctx* ctx, struct net_buf_simple* buf )
{
	struct bt_mesh_etn_fota_upd_cli *updcli = model->user_data;
	int parse_status=0;

	parse_status = fota_upd_cli_extract_server_state_get(buf, &state);

	if(parse_status == 0)
	{
		
		if( state > UPD_SRV_FW_UPDATE_STATE_ERR )
		{
			upd_cli_err_report.opcode = BT_MESH_ETN_FOTA_UPD_SRV_STATE_GET_OP;
			upd_cli_err_report.err_code = FOTA_ERROR_DATA_VALIDATION;
		
			if (updcli->handlers->error_reporting)
			{
				updcli->handlers->error_reporting(updcli, ctx, &upd_cli_err_report);
			}
		}
		else
		{
			if ( updcli->handlers->server_state_get )
			{
				updcli->handlers->server_state_get( &state );
			}
		}		
	}
	else
	{
		LOG_DBG( "data parse error" );
		upd_cli_err_report.opcode = BT_MESH_ETN_FOTA_UPD_SRV_STATE_GET_OP;
		upd_cli_err_report.err_code = FOTA_ERROR_DATA_PARSE;
		
		if (updcli->handlers->error_reporting)
		{
			updcli->handlers->error_reporting(updcli, ctx, &upd_cli_err_report);
		}
	}

	return ( 0 );
}

/*
 *****************************************************************************************
 *		handlers for ETN mesh fota update server
 *****************************************************************************************
 */
const struct bt_mesh_model_op _bt_mesh_etn_fota_upd_cli_op[] = {
	{
		BT_MESH_ETN_FOTA_UPD_PROGRESS_GET_OP,
		BT_MESH_LEN_EXACT( 0 ),
        opcode_handler_fota_upd_cli_progress_get
	},
	{
		BT_MESH_ETN_FOTA_UPD_SRV_STATE_GET_OP,
		BT_MESH_LEN_EXACT( 0 ),
        opcode_handler_fota_upd_cli_server_state_get
	},
	BT_MESH_MODEL_OP_END,
};

int bt_mesh_etn_fota_upd_cli_progress_get_send(struct bt_mesh_etn_fota_upd_cli *updcli, uint16_t addr)
{
	struct bt_mesh_msg_ctx ctx = {
		.addr = addr,
		.app_idx = updcli->model->keys[0],
		.send_ttl = BT_MESH_TTL_DEFAULT,
		.send_rel = true,
	};

	BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_ETN_FOTA_UPD_PROGRESS_GET_OP, 0);
	bt_mesh_model_msg_init(&buf, BT_MESH_ETN_FOTA_UPD_PROGRESS_GET_OP);

	return bt_mesh_model_send(updcli->model, &ctx, &buf, NULL, NULL);
}

int bt_mesh_etn_fota_upd_cli_server_state_get_send(struct bt_mesh_etn_fota_upd_cli *updcli, uint16_t addr)
{
	/* yogesh : to do ttl value */
	
	struct bt_mesh_msg_ctx ctx = {
		.addr = addr,
		.app_idx = updcli->model->keys[0],
		.send_ttl = BT_MESH_TTL_DEFAULT,
		.send_rel = true,
	};

	BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_ETN_FOTA_UPD_SRV_STATE_GET_OP, 0);
	bt_mesh_model_msg_init(&buf, BT_MESH_ETN_FOTA_UPD_SRV_STATE_GET_OP);

	return bt_mesh_model_send(updcli->model, &ctx, &buf, NULL, NULL);
}
