#include <stdio.h>
#include <stdlib.h>
#include <driver/gpio.h>
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// GPIO pin definitions
#define RED_LED_GPIO         GPIO_NUM_21
#define BLUE_LED_GPIO        GPIO_NUM_10
#define RED_BUTTON_GPIO      GPIO_NUM_38
#define BLUE_BUTTON_GPIO     GPIO_NUM_2
#define ACK_BUTTON_RED_GPIO  GPIO_NUM_36
#define ACK_BUTTON_BLUE_GPIO GPIO_NUM_17
// Task configurations
#define TASK_RED_NAME        "controlTaskRed"
#define TASK_RED_STACK_SIZE  (configMINIMAL_STACK_SIZE * 4)
#define TASK_RED_PRIORITY    (tskIDLE_PRIORITY + 1)
#define TASK_BLUE_NAME       "controlTaskBlue"
#define TASK_BLUE_STACK_SIZE (configMINIMAL_STACK_SIZE * 4)
#define TASK_BLUE_PRIORITY   (tskIDLE_PRIORITY + 2)
#define BLINK_TASK_RED_NAME       "blinkTaskRed"
#define BLINK_TASK_RED_STACK_SIZE (configMINIMAL_STACK_SIZE * 4)
#define BLINK_TASK_RED_PRIORITY   (tskIDLE_PRIORITY + 3)
#define BLINK_TASK_BLUE_NAME       "blinkTaskBlue"
#define BLINK_TASK_BLUE_STACK_SIZE (configMINIMAL_STACK_SIZE * 4)
#define BLINK_TASK_BLUE_PRIORITY   (tskIDLE_PRIORITY + 4)
#define ACK_TASK_NAME        "ackTask"
#define ACK_TASK_STACK_SIZE  (configMINIMAL_STACK_SIZE * 4)
#define ACK_TASK_PRIORITY    (tskIDLE_PRIORITY + 5)
// Task function declarations
static void controlTaskRed(void *arg);
static void controlTaskBlue(void *arg);
static void blinkTaskRed(void *arg);
static void blinkTaskBlue(void *arg);
static void ackTask(void *arg);
// Task handles
static TaskHandle_t xTaskRedHandle = NULL;
static TaskHandle_t xTaskBlueHandle = NULL;
static TaskHandle_t xBlinkTaskRedHandle = NULL;
static TaskHandle_t xBlinkTaskBlueHandle = NULL;
static TaskHandle_t xAckTaskHandle = NULL;
// Button and LED states
typedef struct {
    int redButtonState;
    int blueButtonState;
    int ackButtonState;
    int ackButtonRedPressed;
    int ackButtonBluePressed;
} ButtonLEDState;
static ButtonLEDState state = {1, 1, 1, 0, 0};
void app_main(void)
{
    BaseType_t xReturn = pdPASS;
    // Create tasks
    xReturn = xTaskCreate(&controlTaskRed, TASK_RED_NAME, TASK_RED_STACK_SIZE, NULL, TASK_RED_PRIORITY, &xTaskRedHandle);
    xReturn = xTaskCreate(&controlTaskBlue, TASK_BLUE_NAME, TASK_BLUE_STACK_SIZE, NULL, TASK_BLUE_PRIORITY, &xTaskBlueHandle);
    xReturn = xTaskCreate(&blinkTaskRed, BLINK_TASK_RED_NAME, BLINK_TASK_RED_STACK_SIZE, NULL, BLINK_TASK_RED_PRIORITY, &xBlinkTaskRedHandle);
    xReturn = xTaskCreate(&blinkTaskBlue, BLINK_TASK_BLUE_NAME, BLINK_TASK_BLUE_STACK_SIZE, NULL, BLINK_TASK_BLUE_PRIORITY, &xBlinkTaskBlueHandle);
    xReturn = xTaskCreate(&ackTask, ACK_TASK_NAME, ACK_TASK_STACK_SIZE, NULL, ACK_TASK_PRIORITY, &xAckTaskHandle);
    
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}
// Control task for Red LED
static void controlTaskRed(void *arg)
{
    gpio_reset_pin(RED_BUTTON_GPIO);
    gpio_set_direction(RED_BUTTON_GPIO, GPIO_MODE_INPUT);
    gpio_reset_pin(RED_LED_GPIO);
    gpio_set_direction(RED_LED_GPIO, GPIO_MODE_OUTPUT);
    TickType_t lastKeyPressTime = xTaskGetTickCount();
    while (true) {
        int button_pressed = gpio_get_level(RED_BUTTON_GPIO);
        TickType_t currentTime = xTaskGetTickCount();
        if (button_pressed == 0 && state.ackButtonState == 1) {
            if (state.redButtonState == 1 && (currentTime - lastKeyPressTime) > pdMS_TO_TICKS(100)) {
                state.redButtonState = 0;
                lastKeyPressTime = currentTime;
                vTaskResume(xBlinkTaskRedHandle);
            } else if (state.redButtonState == 0) {
                state.redButtonState = 1;
            }
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}
// Control task for Blue LED
static void controlTaskBlue(void *arg)
{
    gpio_reset_pin(BLUE_BUTTON_GPIO);
    gpio_set_direction(BLUE_BUTTON_GPIO, GPIO_MODE_INPUT);
    gpio_reset_pin(BLUE_LED_GPIO);
    gpio_set_direction(BLUE_LED_GPIO, GPIO_MODE_OUTPUT);
    TickType_t lastKeyPressTime = xTaskGetTickCount();
    while (true) {
        int button_pressed = gpio_get_level(BLUE_BUTTON_GPIO);
        TickType_t currentTime = xTaskGetTickCount();
        if (button_pressed == 0 && state.ackButtonState == 1) {
            if (state.blueButtonState == 1 && (currentTime - lastKeyPressTime) > pdMS_TO_TICKS(100)) {
                state.blueButtonState = 0;
                lastKeyPressTime = currentTime;
                vTaskResume(xBlinkTaskBlueHandle);
            } else if (state.blueButtonState == 0) {
                state.blueButtonState = 1;
            }
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}
// Blink task for Red LED
static void blinkTaskRed(void *arg)
{
    while (true) {
        if (state.redButtonState == 0 && state.ackButtonRedPressed == 0) {
            gpio_set_level(RED_LED_GPIO, 1);
            vTaskDelay(pdMS_TO_TICKS(500));
            gpio_set_level(RED_LED_GPIO, 0);
            vTaskDelay(pdMS_TO_TICKS(500));
        } else {
            vTaskDelay(pdMS_TO_TICKS(100));
        }
    }
}
// Blink task for Blue LED
static void blinkTaskBlue(void *arg)
{
    while (true) {
        if (state.blueButtonState == 0 && state.ackButtonBluePressed == 0) {
            gpio_set_level(BLUE_LED_GPIO, 1);
            vTaskDelay(pdMS_TO_TICKS(1000));
            gpio_set_level(BLUE_LED_GPIO, 0);
            vTaskDelay(pdMS_TO_TICKS(1000));
        } else {
            vTaskDelay(pdMS_TO_TICKS(100));
        }
    }
}
// Acknowledge task
static void ackTask(void *arg)
{
    gpio_reset_pin(ACK_BUTTON_RED_GPIO);
    gpio_set_direction(ACK_BUTTON_RED_GPIO, GPIO_MODE_INPUT);
    gpio_reset_pin(ACK_BUTTON_BLUE_GPIO);
    gpio_set_direction(ACK_BUTTON_BLUE_GPIO, GPIO_MODE_INPUT);
    while (true) {
        int red_button_pressed = gpio_get_level(ACK_BUTTON_RED_GPIO);
        int blue_button_pressed = gpio_get_level(ACK_BUTTON_BLUE_GPIO);
        if (red_button_pressed == 0 && state.ackButtonState == 1 && state.redButtonState == 0) {
            state.ackButtonState = 0;
            state.ackButtonRedPressed = 1;
            vTaskSuspend(xBlinkTaskRedHandle);
        } else if (blue_button_pressed == 0 && state.ackButtonState == 1 && state.blueButtonState == 0) {
            state.ackButtonState = 0;
            state.ackButtonBluePressed = 1;
            vTaskSuspend(xBlinkTaskBlueHandle);
        } else if ((red_button_pressed == 1 || blue_button_pressed == 1) && state.ackButtonState == 0) {
            state.ackButtonState = 1;
            state.ackButtonRedPressed = 0;
            state.ackButtonBluePressed = 0;
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}