#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <MPU6050.h>

/* Configuration réseau */
const char* ssid = "Wokwi-GUEST";
const char* password = "";

/* Configuration MQTT sécurisée */
const char* mqtt_server = "57789a6c640d4535a96ce70f90c9d5f4.s1.eu.hivemq.cloud";
const int mqtt_port = 8883;
const char* mqtt_user = "ESP32_Medical";
const char* mqtt_password = "ESP32_Medical";
const char* topic = "medical/sensors";

WiFiClientSecure espClient;
PubSubClient client(espClient);

/* Configuration hardware */
#define BTN_RFID_PIN 4       // Bouton vert sur GPIO4
#define LED_INT_PIN 2        // LED intégrée de l'ESP32
#define LED_ALERTE_PIN 23    // LED d'alerte externe sur GPIO23
#define NTC_PIN 34           // Capteur de température sur GPIO34
#define LED_ON LOW           // Niveau logique pour allumer les LED
#define LED_OFF HIGH

MPU6050 mpu;

void initHardware() {
  pinMode(LED_INT_PIN, OUTPUT);
  pinMode(LED_ALERTE_PIN, OUTPUT);
  pinMode(BTN_RFID_PIN, INPUT_PULLUP);
  digitalWrite(LED_INT_PIN, LED_OFF);
  digitalWrite(LED_ALERTE_PIN, LED_OFF);

  Serial.begin(115200);
  Wire.begin(21, 22); // I2C pins (SDA=21, SCL=22)

  // Initialisation du MPU6050
  mpu.initialize();
  if (!mpu.testConnection()) {
    Serial.println("[ERREUR] MPU6050 non détecté");
    while (1) {
      digitalWrite(LED_ALERTE_PIN, !digitalRead(LED_ALERTE_PIN)); // Clignotement d'erreur
      delay(250);
    }
  }
  Serial.println("[INFO] MPU6050 détecté");
}

void setup_wifi() {
  Serial.print("\nConnexion au WiFi ");
  WiFi.begin(ssid, password);
  int tries = 0;

  while (WiFi.status() != WL_CONNECTED && tries++ < 20) {
    delay(500);
    Serial.print(".");
    digitalWrite(LED_INT_PIN, !digitalRead(LED_INT_PIN)); // Clignote pendant la connexion
  }

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("\n[ERREUR] Impossible de se connecter au WiFi");
    while (1) {
      digitalWrite(LED_ALERTE_PIN, !digitalRead(LED_ALERTE_PIN)); // Clignotement d'erreur rapide
      delay(100);
    }
  }

  digitalWrite(LED_INT_PIN, LED_ON); // LED intégrée allumée = WiFi OK
  Serial.println("\nWiFi connecté | IP: " + WiFi.localIP().toString());
}

void reconnectMQTT() {
  while (!client.connected()) {
    Serial.print("Tentative de connexion MQTT...");
    String clientId = "ESP32Client-" + String(random(0xFFFF), HEX);

    if (client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
      Serial.println("OK");
      digitalWrite(LED_INT_PIN, LED_OFF); // Éteindre LED WiFi quand MQTT connecté
    } else {
      Serial.println("ECHEC (rc=" + String(client.state()) + ")");
      digitalWrite(LED_ALERTE_PIN, LED_ON); // Allumer LED alerte
      delay(5000);
      digitalWrite(LED_ALERTE_PIN, LED_OFF);
    }
  }
}

float readTemperature() {
  // Lecture du capteur NTC (simulation dans Wokwi)
  int rawValue = analogRead(NTC_PIN);
  // Conversion en température (simulation pour Wokwi)
  float temp = map(rawValue, 0, 4095, 350, 380) / 10.0; // 35.0°C - 38.0°C
  return temp;
}

float readVibration() {
  int16_t ax, ay, az;
  mpu.getAcceleration(&ax, &ay, &az);
  // Conversion en m/s² (1g = 9.81 m/s²)
  float vibration = sqrt(ax * ax + ay * ay + az * az) / 16384.0 * 9.81;
  return vibration;
}

float calculateError(float temp) {
  // Simulation d'erreur de mesure (aléatoire ±0.5°C)
  return (random(-50, 50) / 100.0);
}

String generateProductID(bool isRFID) {
  return (isRFID ? "RFID-" : "VIRT-") + String(random(1000, 9999));
}

void publishSensorData() {
  bool rfidDetected = (digitalRead(BTN_RFID_PIN) == LOW);
  float temp = readTemperature();
  float error = calculateError(temp);
  float vibration = readVibration();
  String etape = rfidDetected ? "sterilisation" : "production";

  // Détection des alertes
  bool tempAlert = temp > 37.5;
  bool vibrationAlert = vibration > 10.0;
  bool errorAlert = abs(error) > 0.3;

  String payload = "{"
                   "\"id\":\"" + generateProductID(rfidDetected) + "\","
                   "\"temp\":" + String(temp, 1) + ","
                   "\"error\":" + String(error, 1) + ","
                   "\"vibration\":" + String(vibration, 1) + ","
                   "\"etape\":\"" + etape + "\","
                   "\"alertes\": {"
                     "\"temperature\":" + String(tempAlert ? "true" : "false") + ","
                     "\"vibration\":" + String(vibrationAlert ? "true" : "false") + ","
                     "\"precision\":" + String(errorAlert ? "true" : "false") +
                   "}"
                   "}";

  if (client.publish(topic, payload.c_str())) {
    Serial.println("[MQTT] Données envoyées ✔️");
  } else {
    Serial.println("[MQTT] Échec envoi ❌");
  }

  // Gestion des LED
  bool anyAlert = tempAlert || vibrationAlert || errorAlert;
  digitalWrite(LED_ALERTE_PIN, anyAlert ? LED_ON : LED_OFF);
  
  Serial.println("[DATA] " + payload);
}

void setup() {
  initHardware();
  setup_wifi();

  espClient.setInsecure(); // À remplacer par des certificats en production
  client.setServer(mqtt_server, mqtt_port);
  randomSeed(analogRead(0)); // Initialisation du générateur aléatoire
}

void loop() {
  if (!client.connected()) {
    reconnectMQTT();
  }

  client.loop();
  publishSensorData();
  delay(3000); // Envoi toutes les 3 secondes
}