/*
 * Copyright (c) 2019 Bose Corporation
 * Copyright (c) 2020-2024 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifdef CONFIG_BT_CSIP_SET_MEMBER
#include <zephyr/bluetooth/audio/csip.h>

#include "common.h"

static struct bt_csip_set_member_svc_inst *svc_inst;
extern enum bst_result_t bst_result;
static volatile bool g_locked;
static uint8_t sirk_read_req_rsp = BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT;
struct bt_csip_set_member_register_param param = {
	.set_size = 3,
	.rank = 1,
	.lockable = true,
	/* Using the CSIS test sample SIRK */
	.set_sirk = { 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce,
		      0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 },
};

static void csip_lock_changed_cb(struct bt_conn *conn,
				 struct bt_csip_set_member_svc_inst *svc_inst,
				 bool locked)
{
	printk("Client %p %s the lock\n", conn, locked ? "locked" : "released");
	g_locked = locked;
}

static uint8_t sirk_read_req_cb(struct bt_conn *conn,
				struct bt_csip_set_member_svc_inst *svc_inst)
{
	return sirk_read_req_rsp;
}

static struct bt_csip_set_member_cb csip_cbs = {
	.lock_changed = csip_lock_changed_cb,
	.sirk_read_req = sirk_read_req_cb,
};

static void bt_ready(int err)
{
	uint8_t rsi[BT_CSIP_RSI_SIZE];
	struct bt_data ad[] = {
		BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
		BT_CSIP_DATA_RSI(rsi),
	};

	if (err != 0) {
		FAIL("Bluetooth init failed (err %d)\n", err);
		return;
	}

	printk("Audio Server: Bluetooth initialized\n");

	param.cb = &csip_cbs;

	err = bt_csip_set_member_register(&param, &svc_inst);
	if (err != 0) {
		FAIL("Could not register CSIP (err %d)\n", err);
		return;
	}

	err = bt_csip_set_member_generate_rsi(svc_inst, rsi);
	if (err != 0) {
		FAIL("Failed to generate RSI (err %d)\n", err);
		return;
	}

	err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
	if (err != 0) {
		FAIL("Advertising failed to start (err %d)\n", err);
	}
}

static void test_set_sirk(void)
{
	const uint8_t new_set_sirk[] = {0xff, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce,
					0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45};
	uint8_t tmp_sirk[BT_CSIP_SET_SIRK_SIZE];
	int err;

	printk("Setting new SIRK\n");
	err = bt_csip_set_member_set_sirk(svc_inst, new_set_sirk);
	if (err != 0) {
		FAIL("Failed to set SIRK: %d\n", err);
		return;
	}

	printk("Getting new SIRK\n");
	err = bt_csip_set_member_get_sirk(svc_inst, tmp_sirk);
	if (err != 0) {
		FAIL("Failed to get SIRK: %d\n", err);
		return;
	}

	if (memcmp(new_set_sirk, tmp_sirk, BT_CSIP_SET_SIRK_SIZE) != 0) {
		FAIL("The SIRK set and the SIRK set were different\n");
		return;
	}

	printk("New SIRK correctly set and retrieved\n");
}

static void test_main(void)
{
	int err;

	err = bt_enable(bt_ready);

	if (err != 0) {
		FAIL("Bluetooth init failed (err %d)\n", err);
		return;
	}

	WAIT_FOR_FLAG(flag_connected);

	if (param.lockable) {
		/* Waiting for lock */
		WAIT_FOR_COND(g_locked);
		/* Waiting for lock release */
		WAIT_FOR_COND(!g_locked);
		/* Waiting for lock */
		WAIT_FOR_COND(g_locked);
		/* Waiting for lock release */
		WAIT_FOR_COND(!g_locked);
	}

	WAIT_FOR_UNSET_FLAG(flag_connected);

	err = bt_csip_set_member_unregister(svc_inst);
	if (err != 0) {
		FAIL("Could not unregister CSIP (err %d)\n", err);
		return;
	}
	svc_inst = NULL;

	PASS("CSIP Set member passed: Client successfully disconnected\n");
}

static void test_force_release(void)
{
	int err;

	err = bt_enable(bt_ready);

	if (err != 0) {
		FAIL("Bluetooth init failed (err %d)\n", err);
		return;
	}

	WAIT_FOR_FLAG(flag_connected);

	WAIT_FOR_COND(g_locked);
	printk("Force releasing set\n");
	bt_csip_set_member_lock(svc_inst, false, true);

	WAIT_FOR_UNSET_FLAG(flag_connected);

	err = bt_csip_set_member_unregister(svc_inst);
	if (err != 0) {
		FAIL("Could not unregister CSIP (err %d)\n", err);
		return;
	}
	svc_inst = NULL;

	PASS("CSIP Set member passed: Client successfully disconnected\n");
}

static void test_csip_enc(void)
{
	printk("Running %s\n", __func__);
	sirk_read_req_rsp = BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC;
	test_main();
}

static void test_new_sirk(void)
{
	int err;

	err = bt_enable(bt_ready);

	if (err != 0) {
		FAIL("Bluetooth init failed (err %d)\n", err);
		return;
	}

	WAIT_FOR_FLAG(flag_connected);

	backchannel_sync_send_all();
	backchannel_sync_wait_all();

	test_set_sirk();

	WAIT_FOR_UNSET_FLAG(flag_connected);

	err = bt_csip_set_member_unregister(svc_inst);
	if (err != 0) {
		FAIL("Could not unregister CSIP (err %d)\n", err);
		return;
	}
	svc_inst = NULL;

	PASS("CSIP Set member passed: Client successfully disconnected\n");
}

static void test_args(int argc, char *argv[])
{
	for (size_t argn = 0; argn < argc; argn++) {
		const char *arg = argv[argn];

		if (strcmp(arg, "size") == 0) {
			param.set_size = strtol(argv[++argn], NULL, 10);
		} else if (strcmp(arg, "rank") == 0) {
			param.rank = strtol(argv[++argn], NULL, 10);
		} else if (strcmp(arg, "not-lockable") == 0) {
			param.lockable = false;
		} else if (strcmp(arg, "sirk") == 0) {
			size_t len;

			argn++;

			len = hex2bin(argv[argn], strlen(argv[argn]),
				      param.set_sirk, sizeof(param.set_sirk));
			if (len == 0) {
				FAIL("Could not parse SIRK");
				return;
			}
		} else {
			FAIL("Invalid arg: %s", arg);
		}
	}
}

static const struct bst_test_instance test_connect[] = {
	{
		.test_id = "csip_set_member",
		.test_post_init_f = test_init,
		.test_tick_f = test_tick,
		.test_main_f = test_main,
		.test_args_f = test_args,
	},
	{
		.test_id = "csip_set_member_release",
		.test_post_init_f = test_init,
		.test_tick_f = test_tick,
		.test_main_f = test_force_release,
		.test_args_f = test_args,
	},
	{
		.test_id = "csip_set_member_enc",
		.test_post_init_f = test_init,
		.test_tick_f = test_tick,
		.test_main_f = test_csip_enc,
		.test_args_f = test_args,
	},
	{
		.test_id = "csip_set_member_new_sirk",
		.test_post_init_f = test_init,
		.test_tick_f = test_tick,
		.test_main_f = test_new_sirk,
		.test_args_f = test_args,
	},
	BSTEST_END_MARKER,
};

struct bst_test_list *test_csip_set_member_install(struct bst_test_list *tests)
{
	return bst_add_tests(tests, test_connect);
}
#else

struct bst_test_list *test_csip_set_member_install(struct bst_test_list *tests)
{
	return tests;
}

#endif /* CONFIG_BT_CSIP_SET_MEMBER */
