/*
 * Copyright (c) 2021 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "mesh_cfg.h"
#include "api/mesh.h"

#include "bluetooth/bt_str.h"

#include "net.h"
#include "access.h"
#include "foundation.h"
#include "mesh.h"
#include "sar_cfg_internal.h"

#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
#include "api/mesh_log.h"

#if (CONFIG_BT_MESH_SAR_CFG_CLI)

static struct bt_mesh_sar_cfg_cli *cli;

static int transmitter_status(const struct bt_mesh_model *model,
			       struct bt_mesh_msg_ctx *ctx,
			       struct net_buf_simple *buf)
{
	struct bt_mesh_sar_tx *rsp;

	if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_SAR_CFG_TX_STATUS,
				       ctx->addr, (void **)&rsp)) {
		return 0;
	}

	bt_mesh_sar_tx_decode(buf, rsp);

	LOG_DBG("SAR TX {0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x}",
		rsp->seg_int_step, rsp->unicast_retrans_count,
		rsp->unicast_retrans_without_prog_count,
		rsp->unicast_retrans_int_step, rsp->unicast_retrans_int_inc,
		rsp->multicast_retrans_count, rsp->multicast_retrans_int);

	bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);

	return 0;
}

static int receiver_status(const struct bt_mesh_model *model,
			    struct bt_mesh_msg_ctx *ctx,
			    struct net_buf_simple *buf)
{
	struct bt_mesh_sar_rx *rsp;

	LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
		ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
		bt_hex(buf->data, buf->len));

	if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_SAR_CFG_RX_STATUS,
				       ctx->addr, (void **)&rsp)) {
		return 0;
	}

	bt_mesh_sar_rx_decode(buf, rsp);

	LOG_DBG("SAR RX {0x%02x 0x%02x 0x%02x 0x%02x 0x%02x}", rsp->seg_thresh,
		rsp->ack_delay_inc, rsp->discard_timeout, rsp->rx_seg_int_step,
		rsp->ack_retrans_count);

	bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);

	return 0;
}

const struct bt_mesh_model_op _bt_mesh_sar_cfg_cli_op[] = {
	{ OP_SAR_CFG_TX_STATUS, BT_MESH_LEN_EXACT(BT_MESH_SAR_TX_LEN), transmitter_status },
	{ OP_SAR_CFG_RX_STATUS, BT_MESH_LEN_EXACT(BT_MESH_SAR_RX_LEN), receiver_status },
	BT_MESH_MODEL_OP_END,
};

int32_t bt_mesh_sar_cfg_cli_timeout_get(void)
{
	return cli->timeout;
}

void bt_mesh_sar_cfg_cli_timeout_set(int32_t timeout)
{
	cli->timeout = timeout;
}

static int bt_mesh_sar_cfg_cli_init(const struct bt_mesh_model *model)
{
	if (!bt_mesh_model_in_primary(model)) {
		LOG_ERR("SAR Configuration Client only allowed in primary element");
		return -EINVAL;
	}

	if (!model->rt->user_data) {
		LOG_ERR("No SAR Configuration Client context provided");
		return -EINVAL;
	}

	cli = model->rt->user_data;
	cli->model = model;
	cli->timeout = 2 * MSEC_PER_SEC;

	model->keys[0] = BT_MESH_KEY_DEV_ANY;
	model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY;

	bt_mesh_msg_ack_ctx_init(&cli->ack_ctx);

	return 0;
}

static void bt_mesh_sar_cfg_cli_reset(const struct bt_mesh_model *model)
{
	struct bt_mesh_sar_cfg_cli *model_cli;

	model_cli = model->rt->user_data;

	bt_mesh_msg_ack_ctx_clear(&model_cli->ack_ctx);
}

const struct bt_mesh_model_cb _bt_mesh_sar_cfg_cli_cb = {
	.init = bt_mesh_sar_cfg_cli_init,
	.reset = bt_mesh_sar_cfg_cli_reset,
};

int bt_mesh_sar_cfg_cli_transmitter_get(uint16_t net_idx, uint16_t addr,
					struct bt_mesh_sar_tx *rsp)
{
	BT_MESH_MODEL_BUF_DEFINE(msg, OP_SAR_CFG_TX_GET, 0);
	struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
	int err;

	err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_SAR_CFG_TX_STATUS, addr, rsp);
	if (err) {
		return err;
	}

	bt_mesh_model_msg_init(&msg, OP_SAR_CFG_TX_GET);

	err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL);
	if (err) {
		LOG_ERR("model_send() failed (err %d)", err);
		bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
		return err;
	}

	return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}

int bt_mesh_sar_cfg_cli_transmitter_set(uint16_t net_idx, uint16_t addr,
					const struct bt_mesh_sar_tx *set,
					struct bt_mesh_sar_tx *rsp)
{
	BT_MESH_MODEL_BUF_DEFINE(msg, OP_SAR_CFG_TX_SET, BT_MESH_SAR_TX_LEN);
	struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
	int err;

	err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_SAR_CFG_TX_STATUS, addr, rsp);
	if (err) {
		return err;
	}

	bt_mesh_model_msg_init(&msg, OP_SAR_CFG_TX_SET);
	bt_mesh_sar_tx_encode(&msg, set);

	err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL);
	if (err) {
		LOG_ERR("model_send() failed (err %d)", err);
		bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
		return err;
	}

	return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}

int bt_mesh_sar_cfg_cli_receiver_get(uint16_t net_idx, uint16_t addr,
				     struct bt_mesh_sar_rx *rsp)
{
	BT_MESH_MODEL_BUF_DEFINE(msg, OP_SAR_CFG_RX_GET, 0);
	struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
	int err;

	err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_SAR_CFG_RX_STATUS, addr, rsp);
	if (err) {
		return err;
	}

	bt_mesh_model_msg_init(&msg, OP_SAR_CFG_RX_GET);

	err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL);
	if (err) {
		LOG_ERR("model_send() failed (err %d)", err);
		bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
		return err;
	}

	return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}

int bt_mesh_sar_cfg_cli_receiver_set(uint16_t net_idx, uint16_t addr,
				     const struct bt_mesh_sar_rx *set,
				     struct bt_mesh_sar_rx *rsp)
{
	BT_MESH_MODEL_BUF_DEFINE(msg, OP_SAR_CFG_RX_SET, BT_MESH_SAR_RX_LEN);
	struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
	int err;

	err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_SAR_CFG_RX_STATUS, addr, rsp);
	if (err) {
		return err;
	}

	bt_mesh_model_msg_init(&msg, OP_SAR_CFG_RX_SET);
	bt_mesh_sar_rx_encode(&msg, set);

	err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL);
	if (err) {
		LOG_ERR("model_send() failed (err %d)", err);
		bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
		return err;
	}

	return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}

#endif // CONFIG_BT_MESH_SAR_CFG_CLI