#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>

#include "my_custom.h"

#define CUSTOM_SVC_ATTR_COUNT 5 // total number of attribute in the service

static bool notify_confirm_enabled = false;

static uint32_t last_received_value;
const struct bt_gatt_attr *confirm_attr = NULL;

static ssize_t write_char_cb(struct bt_conn *conn,
			     const struct bt_gatt_attr *attr,
			     const void *buf, uint16_t len,
			     uint16_t offset, uint8_t flags)
{
	if (len != sizeof(uint32_t)) {
		printk("Donnée inattendue\n");
		return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
	}

	memcpy(&last_received_value, buf, sizeof(uint32_t));
	printk("Received value from the central : %u\n", last_received_value);

	k_sleep(K_MSEC(200));
	if(notify_confirm_enabled && confirm_attr)	{
		int err = my_custom_send_sensor_notify(last_received_value);
		printk("Send notify err : %d\n", err);
	} else	{
		printk("Notify disabled -> no sending\n");
	}

	return len;
}

/* STEP 13 - Define the configuration change callback function for the CONFIRM characteristic */
static void customcb_ccc_confirm_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
	notify_confirm_enabled = (value == BT_GATT_CCC_NOTIFY);
 	if (value == BT_GATT_CCC_NOTIFY) {
		printk("CCCD changé : CONFIRM notify : activé\n");

		uint32_t dummy = 0x00000000;
		int err = bt_gatt_notify(NULL, confirm_attr, &dummy, sizeof(dummy));
		printk("Envoi notification d'activation : err = %d\n", err);
	}
} 

/* Custom Service Declaration */
BT_GATT_SERVICE_DEFINE(custom_svc,
	BT_GATT_PRIMARY_SERVICE(BT_UUID_CUSTOM_SERVICE),
	BT_GATT_CHARACTERISTIC(BT_UUID_CUSTOM_WRITE,
			    BT_GATT_CHRC_WRITE,
			    BT_GATT_PERM_WRITE,
			    NULL, write_char_cb, NULL),
    /* STEP 12 - Create and add the CUSTOM characteristic and its CCCD  */
	BT_GATT_CHARACTERISTIC(BT_UUID_CUSTOM_CONFIRM,
				BT_GATT_CHRC_NOTIFY,
    			BT_GATT_PERM_NONE,
   				NULL, NULL, NULL),
	BT_GATT_CCC(customcb_ccc_confirm_cfg_changed,
		BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
);

/* STEP 14 - Define the function to send notifications for the CUSTOM characteristic */
int my_custom_send_sensor_notify(uint32_t sensor_value)
{
	if (!notify_confirm_enabled || !confirm_attr) {
		return -EACCES;
	}  
	return bt_gatt_notify(NULL, confirm_attr, 
	&sensor_value, sizeof(sensor_value));
}

int my_custom_init(void)
{
	const struct bt_gatt_attr *attr;

	attr = bt_gatt_find_by_uuid(custom_svc.attrs,
	                            CUSTOM_SVC_ATTR_COUNT,  
	                            BT_UUID_CUSTOM_CONFIRM);
	if (!attr) {
		printk("Caractéristique CONFIRM introuvable par UUID\n");
		return -ENOENT;
	}

	/* L’attribut retourné est la valeur (pas le CHRC), donc utilisable directement */
	confirm_attr = attr;
	printk("confirm_attr found with bt_gatt_find_by_uuid, handle = 0x%04x\n", attr->handle);
	return 0;
}
