#include <stm32c0xx_hal.h>
#include "dht22.h"         // Include the DHT22 library header
#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
#include <semphr.h>
#include <stdio.h>

// GPIO Pins Definition
#define HUMIDITY_SENSOR1_PIN    GPIO_PIN_0 // Humidity Sensor 1 on PA0
#define HUMIDITY_SENSOR2_PIN    GPIO_PIN_1 // Humidity Sensor 2 on PA1
#define VALVE1_PIN              GPIO_PIN_5 // Simulated Valve 1 (LED) on PA5
#define VALVE2_PIN              GPIO_PIN_6 // Simulated Valve 2 (LED) on PA6
#define EMERGENCY_BUTTON_PIN    GPIO_PIN_4 // Emergency Stop Button on PA4
#define POTENTIOMETER_PIN       GPIO_PIN_3 // Potentiometer on PB3
#define EMERGENCY_LED_PIN       GPIO_PIN_7 // Red LED for Emergency Stop on PA7

// Global Variables
SemaphoreHandle_t emergencySemaphore;
SemaphoreHandle_t humidityThresholdMutex;
QueueHandle_t humidityQueue;
uint8_t humidityThreshold = 50; // Initial humidity threshold (50%)

// DHT22 objects
DHT22 dht1;
DHT22 dht2;

// Function Prototypes
void SystemClock_Config(void);
void GPIO_Init(void);
void ReadHumidityTask(void *pvParameters);
void ValveControlTask(void *pvParameters);
void EmergencyButtonTask(void *pvParameters);
void PotentiometerTask(void *pvParameters);
void LogEvent(const char* event);

// Main Function
int main(void) {
    // HAL Initialization
    HAL_Init();

    // System Clock Configuration
    SystemClock_Config();

    // GPIO Initialization
    GPIO_Init();

    // Initialize DHT22 sensors
    dht22_init(&dht1, GPIOA, HUMIDITY_SENSOR1_PIN);
    dht22_init(&dht2, GPIOA, HUMIDITY_SENSOR2_PIN);

    // Create FreeRTOS resources
    emergencySemaphore = xSemaphoreCreateBinary();
    humidityQueue = xQueueCreate(10, sizeof(uint8_t));
    humidityThresholdMutex = xSemaphoreCreateMutex();

    if (!humidityThresholdMutex || !humidityQueue || !emergencySemaphore) {
        LogEvent("Error creating FreeRTOS resources.");
        while (1);
    }

    // Create FreeRTOS tasks
    xTaskCreate(ReadHumidityTask, "Read Humidity", 128, NULL, 1, NULL);
    xTaskCreate(ValveControlTask, "Valve Control", 128, NULL, 2, NULL);
    xTaskCreate(EmergencyButtonTask, "Emergency Button", 128, NULL, 3, NULL);
    xTaskCreate(PotentiometerTask, "Potentiometer", 128, NULL, 1, NULL);

    // Start the FreeRTOS scheduler
    vTaskStartScheduler();

    // If the scheduler fails
    while (1);
}

// GPIO Initialization
void GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    // Configure humidity sensors and emergency button as input
    GPIO_InitStruct.Pin = HUMIDITY_SENSOR1_PIN | HUMIDITY_SENSOR2_PIN | EMERGENCY_BUTTON_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // Configure valves and emergency LED as output
    GPIO_InitStruct.Pin = VALVE1_PIN | VALVE2_PIN | EMERGENCY_LED_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // Configure potentiometer as input
    GPIO_InitStruct.Pin = POTENTIOMETER_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

// Humidity Reading Task
void ReadHumidityTask(void *pvParameters) {
    float humidity1, humidity2;

    while (1) {
        // Read humidity from DHT22 sensors
        if (dht22_read(&dht1, &humidity1, NULL) && dht22_read(&dht2, &humidity2, NULL)) {
            xSemaphoreTake(humidityThresholdMutex, portMAX_DELAY);
            uint8_t currentThreshold = humidityThreshold;
            xSemaphoreGive(humidityThresholdMutex);

            // Send to queue if below threshold
            if (humidity1 < currentThreshold) {
                uint8_t zone = 1;
                xQueueSend(humidityQueue, &zone, portMAX_DELAY);
            }
            if (humidity2 < currentThreshold) {
                uint8_t zone = 2;
                xQueueSend(humidityQueue, &zone, portMAX_DELAY);
            }
        } else {
            LogEvent("DHT22 read error.");
        }

        vTaskDelay(pdMS_TO_TICKS(5000)); // 5-second interval
    }
}

// Valve Control Task
void ValveControlTask(void *pvParameters) {
    uint8_t zone;

    while (1) {
        if (xQueueReceive(humidityQueue, &zone, portMAX_DELAY)) {
            if (zone == 1) {
                HAL_GPIO_WritePin(GPIOA, VALVE1_PIN, GPIO_PIN_SET);
                LogEvent("Valve 1 activated.");
                vTaskDelay(pdMS_TO_TICKS(10000));
                HAL_GPIO_WritePin(GPIOA, VALVE1_PIN, GPIO_PIN_RESET);
                LogEvent("Valve 1 deactivated.");
            } else if (zone == 2) {
                HAL_GPIO_WritePin(GPIOA, VALVE2_PIN, GPIO_PIN_SET);
                LogEvent("Valve 2 activated.");
                vTaskDelay(pdMS_TO_TICKS(10000));
                HAL_GPIO_WritePin(GPIOA, VALVE2_PIN, GPIO_PIN_RESET);
                LogEvent("Valve 2 deactivated.");
            }
        }
    }
}

// Emergency Button Task
void EmergencyButtonTask(void *pvParameters) {
    while (1) {
        if (HAL_GPIO_ReadPin(GPIOA, EMERGENCY_BUTTON_PIN) == GPIO_PIN_SET) {
            HAL_GPIO_WritePin(GPIOA, VALVE1_PIN | VALVE2_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(GPIOA, EMERGENCY_LED_PIN, GPIO_PIN_SET);
            LogEvent("Emergency stop activated!");
            xSemaphoreGive(emergencySemaphore);
        }
        vTaskDelay(pdMS_TO_TICKS(50)); // Debouncing
    }
}

// Potentiometer Task
void PotentiometerTask(void *pvParameters) {
    while (1) {
        uint8_t potentiometerValue = HAL_GPIO_ReadPin(GPIOB, POTENTIOMETER_PIN) ? 60 : 40;

        xSemaphoreTake(humidityThresholdMutex, portMAX_DELAY);
        humidityThreshold = potentiometerValue;
        xSemaphoreGive(humidityThresholdMutex);

        LogEvent("Humidity threshold updated.");
        vTaskDelay(pdMS_TO_TICKS(5000));
    }
}

// Event Logging Function
void LogEvent(const char* event) {
    printf("%s\n", event);
}

// System Clock Configuration (Placeholder)
void SystemClock_Config(void) {
    // Placeholder for clock configuration
}