#include <SystemK.h>
#include <driver/gpio.h>
#include <iot_button.h>
#include <freertos/FreeRTOS.h>
#include <freertos/portmacro.h>

static const char *TAG = "Switches";

// GPIO assignments
#define TRIGGER_GPIO GPIO_NUM_1
#define ACCESSORY_GPIO GPIO_NUM_4

static button_handle_t Trigger_Button;
static button_config_t Trigger_Button_Config = {
    .type = BUTTON_TYPE_GPIO,
    .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
    .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
    .gpio_button_config = {
        .gpio_num = TRIGGER_GPIO,
        .active_level = 0,
    },
};

static button_handle_t Accessory_Button;
static button_config_t Accessory_Button_Config = {
    .type = BUTTON_TYPE_GPIO,
    .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
    .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
    .gpio_button_config = {
        .gpio_num = ACCESSORY_GPIO,
        .active_level = 0,
    },
};

static TickType_t TicksAtTriggerPress = 0;
static TickType_t TicksAtAccessoryPress = 0;
static TickType_t TicksAtAccessoryRelease = 0;

static void trigger_press_cb(void *arg, void *usr_data)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    TicksAtTriggerPress = xTaskGetTickCountFromISR();
    KEvent_T switch_event = {.ID = KEVENT_TRIGGER_SWITCH_PRESSED, .Data = NULL};
    Post_KEvent_From_ISR(&switch_event, &xHigherPriorityTaskWoken);
}

static void trigger_release_cb(void *arg, void *usr_data)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    uint32_t triggerPressDurationInms = pdTICKS_TO_MS(xTaskGetTickCountFromISR() - TicksAtTriggerPress);
    KEvent_T switch_event = {.ID = KEVENT_TRIGGER_SWITCH_RELEASED, .Data = (void *) triggerPressDurationInms};
    Post_KEvent_From_ISR(&switch_event, &xHigherPriorityTaskWoken);
}

static void accessory_press_cb(void *arg, void *usr_data)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    TicksAtAccessoryPress = xTaskGetTickCountFromISR();
    uint32_t accessoryTimeReleasedInms = pdTICKS_TO_MS(xTaskGetTickCountFromISR() - TicksAtAccessoryRelease);
    KEvent_T switch_event = {.ID = KEVENT_ACCESSORY_SWITCH_PRESSED, .Data = (void *) accessoryTimeReleasedInms};
    Post_KEvent_From_ISR(&switch_event, &xHigherPriorityTaskWoken);
}

static void accessory_release_cb(void *arg, void *usr_data)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    TicksAtAccessoryRelease = xTaskGetTickCountFromISR();
    uint32_t accessoryPressDurationInms = pdTICKS_TO_MS(xTaskGetTickCountFromISR() - TicksAtAccessoryPress);
    KEvent_T switch_event = {.ID = KEVENT_ACCESSORY_SWITCH_RELEASED, .Data = (void *) accessoryPressDurationInms};
    Post_KEvent_From_ISR(&switch_event, &xHigherPriorityTaskWoken);
}

void Initialize_Switches(void)
{
    KLOG_INFO(TAG, "Initializing Switches...");

    Trigger_Button = iot_button_create(&Trigger_Button_Config);
    assert(Trigger_Button);

    Accessory_Button = iot_button_create(&Accessory_Button_Config);
    assert(Accessory_Button);

    iot_button_register_cb(Trigger_Button, BUTTON_PRESS_DOWN, trigger_press_cb, NULL);
    iot_button_register_cb(Trigger_Button, BUTTON_PRESS_UP, trigger_release_cb, NULL);

    iot_button_register_cb(Accessory_Button, BUTTON_PRESS_DOWN, accessory_press_cb, NULL);
    iot_button_register_cb(Accessory_Button, BUTTON_PRESS_UP, accessory_release_cb, NULL);
}
