/* src/main.c */
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/uuid.h>
#include <string.h>
#include <stdio.h>

#include "../inc/uart.h"

LOG_MODULE_REGISTER(aram_app, LOG_LEVEL_INF);

#define VER_STRING  "Ver: Dev 007 -RC007"
#define HELP_STRING "Commands: Ver, Id, LedOn, LedOff, Reset, Help\r\n"

/* GPIO Setup */
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

/* Varicite reset pin - P1.04 on gpio1, via zephyr,user node */
//static const struct gpio_dt_spec varicite_reset_pin =
//    GPIO_DT_SPEC_GET(DT_PATH(zephyr_user), varicite_reset_gpios);

static const struct gpio_dt_spec varicite_reset_pin =
   GPIO_DT_SPEC_GET_OR(DT_NODELABEL(varicite_reset_pin), gpios, {0});

extern struct k_msgq uart3_msgq;
extern const struct bt_gatt_service_static nus_svc;

/* NUS UUIDs */
#define BT_UUID_NUS_VAL    BT_UUID_128_ENCODE(0x6e400001, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e)
#define BT_UUID_NUS_TX_VAL BT_UUID_128_ENCODE(0x6e400003, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e)
#define BT_UUID_NUS_RX_VAL BT_UUID_128_ENCODE(0x6e400002, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e)

static struct bt_uuid_128 nus_tx_uuid = BT_UUID_INIT_128(BT_UUID_NUS_TX_VAL);
static struct bt_uuid_128 nus_rx_uuid = BT_UUID_INIT_128(BT_UUID_NUS_RX_VAL);
static bool notify_enabled;

/* ---------------------------------------------------------------
 * Shared command handler - called from both BLE and UART3.
 * response[] is filled with the reply string (null-terminated).
 * Returns the length of the response string.
 * --------------------------------------------------------------- */
static int  handle_command(const char *cmd_in, char *response, size_t resp_size)
{
    // 1. Create a mutable pointer and skip leading whitespace
    const char *cmd = cmd_in;
    while (isspace((unsigned char)*cmd)) {
        cmd++;
    }

    // 2. Handle trailing CR/LF/Spaces by creating a local copy or 
    // using a temporary buffer if cmd_in needs to stay immutable.
    // For simplicity, let's assume we can work with a local stack copy:
    char clean_cmd[64]; 
    strncpy(clean_cmd, cmd, sizeof(clean_cmd) - 1);
    clean_cmd[sizeof(clean_cmd) - 1] = '\0';

    // Trim trailing whitespace/CR/LF
    char *end = clean_cmd + strlen(clean_cmd) - 1;
    while (end >= clean_cmd && isspace((unsigned char)*end)) {
        *end = '\0';
        end--;
    }

    // --- Now use 'clean_cmd' for your logic ---

    if (strcmp(clean_cmd, "Ver") == 0) {
        snprintf(response, resp_size, VER_STRING "\r\n");

    } else if (strcmp(clean_cmd, "Id") == 0) {
        snprintf(response, resp_size, "Id:%s\r\n", CONFIG_BOARD);

    } else if (strcmp(clean_cmd, "LedOn") == 0) {
        gpio_pin_set_dt(&led, 1);
        snprintf(response, resp_size, "LED:ON\r\n");

    } else if (strcmp(clean_cmd, "LedOff") == 0) {
        gpio_pin_set_dt(&led, 0);
        snprintf(response, resp_size, "LED:OFF\r\n");

    } else if (strcmp(clean_cmd, RESET_CMD_ASC) == 0) {
        snprintf(response, resp_size, "Reset:%s", CONFIG_BOARD);
        return 99; 

    } else if (strcmp(clean_cmd, "Help") == 0) {
        snprintf(response, resp_size, HELP_STRING);

    } else {
        snprintf(response, resp_size, "Unknown:%s\r\n", clean_cmd);
    }

    return strlen(response);
}

/* ---------------------------------------------------------------
 * Hardware reset sequence - hold reset pin for 5 s
 * --------------------------------------------------------------- */
void trigger_varicite_reset(const char *source)
{
    LOG_INF("Reset triggered by %s", source);
    gpio_pin_set_dt(&led, 1);
    gpio_pin_set_dt(&varicite_reset_pin, 1);
    k_msleep(5000);
    gpio_pin_set_dt(&led, 0);
    gpio_pin_set_dt(&varicite_reset_pin, 0);
    LOG_INF("Reset complete.");
}

/* ---------------------------------------------------------------
 * BLE NUS callbacks
 * --------------------------------------------------------------- */
static void nus_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
    notify_enabled = (value == BT_GATT_CCC_NOTIFY);
    LOG_INF("BLE notifications %s", notify_enabled ? "enabled" : "disabled");
}

static ssize_t nus_rx_received(struct bt_conn *conn,
                               const struct bt_gatt_attr *attr,
                               const void *buf, uint16_t len,
                               uint16_t offset, uint8_t flags)
{
    char incoming[32];
    char response[128];
    uint16_t copy_len = MIN(len, sizeof(incoming) - 1);

    memcpy(incoming, buf, copy_len);
    incoming[copy_len] = '\0';
    LOG_INF("BLE RX: %s, - %d", incoming,strlen(incoming));

    int cmd_result = handle_command(incoming, response, sizeof(response));

    if (notify_enabled) {
        bt_gatt_notify(NULL, &nus_svc.attrs[2], response, strlen(response));
        LOG_INF("BLE TX: %s", response);
    }

    /* Perform reset after sending the response */
    if (cmd_result == 99) {
        trigger_varicite_reset("BLE");
    }

    return len;
}

BT_GATT_SERVICE_DEFINE(nus_svc,
    BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_128(BT_UUID_NUS_VAL)),
    BT_GATT_CHARACTERISTIC(&nus_tx_uuid.uuid, BT_GATT_CHRC_NOTIFY,
                           BT_GATT_PERM_NONE, NULL, NULL, NULL),
    BT_GATT_CCC(nus_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
    BT_GATT_CHARACTERISTIC(&nus_rx_uuid.uuid,
                           BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
                           BT_GATT_PERM_WRITE, NULL, nus_rx_received, NULL),
);

/* ---------------------------------------------------------------
 * UART3 command handler thread
 * Reads lines from uart3_msgq (filled by uart3 ISR in uart.c)
 * and sends responses back over UART3.
 * --------------------------------------------------------------- */
void uart3_handler_thread(void *p1, void *p2, void *p3)
{
    char cmd[128];
    char response[128];

    LOG_INF("UART3 handler thread started");
    int cmd_resp = -1;

    while (1) {
        if (k_msgq_get(&uart3_msgq, &cmd, K_FOREVER) == 0) {
            LOG_INF("UART3 RX: %s", cmd);

            cmd_resp = handle_command(cmd, response, sizeof(response));

            /* Send response over UART3 */
            print_uart3(response);

            LOG_INF("UART3 TX ---: %s", response);

            /* Perform reset after sending the response */
            if (cmd_resp == 99) {
                trigger_varicite_reset("UART3");
            }
        }
    }
}

/* ---------------------------------------------------------------
 * UART2 (modem) polling thread - watches for SMS reset command
 * --------------------------------------------------------------- */
void uart2_poll_thread(void *p1, void *p2, void *p3)
{
    while (1) {
        if (send_wait_resp("AT+CMGL=\"REC UNREAD\"", RESET_CMD) == 0) {
            LOG_INF("RESET MESSAGE DETECTED via modem");
            trigger_varicite_reset("Modem");
        }
        k_msleep(2000);
    }
}

K_THREAD_DEFINE(u2_tid, 1024, uart2_poll_thread,   NULL, NULL, NULL, 7, 0, 0);
K_THREAD_DEFINE(u3_tid, 1024, uart3_handler_thread, NULL, NULL, NULL, 7, 0, 0);

/* ---------------------------------------------------------------
 * Bluetooth ready callback
 * --------------------------------------------------------------- */
static void bt_ready(int err)
{
    if (err) {
        LOG_ERR("Bluetooth init failed (err %d)", err);
        return;
    }
    bt_le_adv_start(BT_LE_ADV_CONN_NAME, NULL, 0, NULL, 0);
    LOG_INF("BLE advertising started");
}

int io_init(void)
{
	if (!gpio_is_ready_dt(&led)) return -1;
	gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	gpio_pin_set_dt(&led, 0);

	if (!gpio_is_ready_dt(&varicite_reset_pin)) {
		LOG_ERR("varicite_reset_pin not ready");
		return -1;
	}
	gpio_pin_configure_dt(&varicite_reset_pin, GPIO_OUTPUT_INACTIVE | GPIO_PULL_DOWN);
	gpio_pin_set_dt(&varicite_reset_pin, 0);
    
	LOG_INF("varicite_reset_pin P1.04 configured LOW");

	return 0;
}

/* ---------------------------------------------------------------
 * main
 * --------------------------------------------------------------- */
int main(void)
{
    LOG_INF("Starting ARAM application on %s", CONFIG_BOARD);

	io_init();	
    uart_init();
    bt_enable(bt_ready);

    return 0;
}
