#include "stm32f3xx_hal.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "stdio.h"
#include "DHT.h"

// Définition des pins pour les LEDs, bouton et potentiomètre
#define LED1_PIN    GPIO_PIN_0  // Première LED (Zone 1)
#define LED2_PIN    GPIO_PIN_1  // Deuxième LED (Zone 2)
#define BUTTON_PIN  GPIO_PIN_13 // Bouton poussoir pour arrêt d'urgence
#define POT_PIN     GPIO_PIN_2  // Potentiomètre pour ajuster le seuil

// Définition des pins pour les capteurs DHT22
#define DHT22_PIN_1 GPIO_PIN_5  // Pin pour le premier capteur DHT22 (Zone 1)
#define DHT22_PIN_2 GPIO_PIN_6  // Pin pour le second capteur DHT22 (Zone 2)

// Paramètres
#define HUMIDITY_THRESHOLD 50  // Seuil d'humidité par défaut
#define HUMIDITY_PERIOD_MS 5000 // Période de lecture des capteurs d'humidité en ms
#define VALVE_OPEN_TIME_MS 10000 // Durée d'ouverture de la vanne en ms

// Structures pour les messages
typedef enum {
    ZONE1,
    ZONE2
} Zone;

typedef struct {
    Zone zone;
} ValveMessage;

// Variables globales
SemaphoreHandle_t emergencySemaphore;
QueueHandle_t valveQueue;
int humidityThreshold = HUMIDITY_THRESHOLD; // Seuil d'humidité

// Fonction d'initialisation de l'UART (simulation)
void UART_Init(void) {
    // Initialisation UART pour la journalisation
    // HAL_UART_Init(&huart2);
}

// Fonction de journalisation
void UART_Printf(const char *message) {
    // Simulation de l'affichage sur le moniteur série
    printf("%s\n", message);
}

// Initialisation des GPIOs
void GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // Initialisation des LEDs (simuler les vannes)
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.Pin = LED1_PIN | LED2_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // Initialisation du bouton poussoir pour l'arrêt d'urgence
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitStruct.Pin = BUTTON_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    // Initialisation du potentiomètre
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.Pin = POT_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // Initialisation des capteurs DHT22 (pour chaque zone)
    DHT_init(DHT22_PIN_1);
    DHT_init(DHT22_PIN_2);
}

// Fonction pour lire l'humidité des capteurs DHT22
int ReadHumidityDHT(int sensor_pin) {
    float humidity = 0.0;
    if (sensor_pin == DHT22_PIN_1) {
        humidity = DHT_readHumidity(DHT22_PIN_1);
    } else if (sensor_pin == DHT22_PIN_2) {
        humidity = DHT_readHumidity(DHT22_PIN_2);
    }
    return (int)humidity;
}

// Tâche pour la surveillance de l'humidité
void HumidityTask(void *pvParameters) {
    int humidityZone1, humidityZone2;

    while (1) {
        // Lecture des capteurs DHT22 pour l'humidité
        humidityZone1 = ReadHumidityDHT(DHT22_PIN_1); // Zone 1
        humidityZone2 = ReadHumidityDHT(DHT22_PIN_2); // Zone 2

        // Comparaison avec le seuil d'humidité
        if (humidityZone1 < humidityThreshold) {
            ValveMessage msg = {ZONE1};
            xQueueSend(valveQueue, &msg, portMAX_DELAY); // Envoi du message dans la queue pour activer la vanne de la zone 1
        }
        if (humidityZone2 < humidityThreshold) {
            ValveMessage msg = {ZONE2};
            xQueueSend(valveQueue, &msg, portMAX_DELAY); // Envoi du message dans la queue pour activer la vanne de la zone 2
        }

        // Attente de 5 secondes avant la prochaine lecture
        vTaskDelay(pdMS_TO_TICKS(HUMIDITY_PERIOD_MS));
    }
}

// Tâche pour activer les vannes
void ValveControlTask(void *pvParameters) {
    ValveMessage msg;
    while (1) {
        if (xQueueReceive(valveQueue, &msg, portMAX_DELAY)) {
            // Activation de la LED en fonction de la zone
            if (msg.zone == ZONE1) {
                HAL_GPIO_WritePin(GPIOB, LED1_PIN, GPIO_PIN_SET);  // Activer LED 1
                UART_Printf("Zone 1 arrosage activé");
            } else if (msg.zone == ZONE2) {
                HAL_GPIO_WritePin(GPIOB, LED2_PIN, GPIO_PIN_SET);  // Activer LED 2
                UART_Printf("Zone 2 arrosage activé");
            }

            // Attente de la durée d'activation de la vanne
            vTaskDelay(pdMS_TO_TICKS(VALVE_OPEN_TIME_MS));

            // Désactivation de la LED après la durée
            if (msg.zone == ZONE1) {
                HAL_GPIO_WritePin(GPIOB, LED1_PIN, GPIO_PIN_RESET);  // Désactiver LED 1
            } else if (msg.zone == ZONE2) {
                HAL_GPIO_WritePin(GPIOB, LED2_PIN, GPIO_PIN_RESET);  // Désactiver LED 2
            }
        }
    }
}

// Tâche pour gérer l'arrêt d'urgence
void EmergencyStopTask(void *pvParameters) {
    while (1) {
        if (HAL_GPIO_ReadPin(GPIOC, BUTTON_PIN) == GPIO_PIN_SET) {
            // Si le bouton d'urgence est pressé
            xSemaphoreGive(emergencySemaphore); // Signaler un arrêt d'urgence
            UART_Printf("Arrêt d'urgence activé");
            // Allumer la LED rouge pour l'arrêt d'urgence
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET); // Exemple LED rouge
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

// Tâche pour ajuster le seuil d'humidité
void ThresholdTask(void *pvParameters) {
    while (1) {
        // Simulation de la lecture de la valeur du potentiomètre pour ajuster le seuil
        int potValue = HAL_GPIO_ReadPin(GPIOA, POT_PIN); // Simulation de la lecture
        humidityThreshold = (potValue / 4095.0) * 100; // Conversion en pourcentage

        // Journalisation de la nouvelle valeur du seuil
        char msg[50];
        snprintf(msg, sizeof(msg), "Nouveau seuil d'humidité: %d", humidityThreshold);
        UART_Printf(msg);

        // Attente avant la prochaine lecture du potentiomètre
        vTaskDelay(pdMS_TO_TICKS(5000));
    }
}

// Tâche pour gérer le sémaphore d'urgence
void EmergencySemaphoreTask(void *pvParameters) {
    while (1) {
        if (xSemaphoreTake(emergencySemaphore, portMAX_DELAY)) {
            // Fermer toutes les vannes et éteindre les LEDs
            HAL_GPIO_WritePin(GPIOB, LED1_PIN | LED2_PIN, GPIO_PIN_RESET);
            UART_Printf("Toutes les vannes fermées");
            // Allumer la LED rouge d'urgence
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
        }
    }
}

int main(void) {
    HAL_Init();
    UART_Init();
    GPIO_Init();

    // Création des sémaphores et queues
    emergencySemaphore = xSemaphoreCreateBinary();
    valveQueue = xQueueCreate(10, sizeof(ValveMessage));

    // Création des tâches
    xTaskCreate(HumidityTask, "HumidityTask", 128, NULL, 1, NULL);
    xTaskCreate(ValveControlTask, "ValveControlTask", 128, NULL, 1, NULL);
    xTaskCreate(EmergencyStopTask, "EmergencyStopTask", 128, NULL, 1, NULL);
    xTaskCreate(ThresholdTask, "ThresholdTask", 128, NULL, 1, NULL);
    xTaskCreate(EmergencySemaphoreTask, "EmergencySemaphoreTask", 128, NULL, 1, NULL);

    // Démarrage du scheduler FreeRTOS
    vTaskStartScheduler();

    while (1) {
        // Code principal
    }
}