#include <WiFi.h>
#include "PubSubClient.h"
#include "DHTesp.h"
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <DHT.h>
#include <Keypad.h>

// --- Cấu hình ---
#define DHT_PIN 15
#define DHT_TYPE DHT22
#define LCD_SDA 21
#define LCD_SCL 22
#define LDR_PIN 4
#define PIR_PIN 2
#define LED_LOSUOI 16
#define LED_DIEUHOA 17
#define LED_REM 5
#define LED_MOCUA 19
#define LED_CANHBAO 23
#define LED_DEN 18

// WiFi và MQTT
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;
const char* MQTT_ID = "c5afa5ae-d3a0-48b7-b850-92015a281909";
WiFiClient espClient;
PubSubClient client(espClient);

// Chủ đề MQTT
const char* topicTempHumidity = "Iot/Nhietdoam";
const char* topicLightStatus = "Iot/Rem";
const char* topicMotionStatus = "Iot/Den";
const char* topicDoorStatus = "Iot/Cua";
const char* topicKeypadStatus = "Iot/Keypad";

// Cảm biến DHT
DHTesp dhtSensor;
DHT dht(DHT_PIN, DHT_TYPE);

// LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Keypad
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {13, 12, 14, 27};  
byte colPins[COLS] = {26, 25, 33, 32};  
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

// Biến ngưỡng và trạng thái
float tempThresholdLow = 18.0;
float tempThresholdHigh = 30.0;
int delayTime = 5000; // Mặc định 5 giây
int lightThreshold = 800;
int timeoutLight = 10000; // Thời gian chờ cho đèn

String correctPassword = "1234";
String enteredPassword = "";
int failCount = 0;
int maxFail = 3;
unsigned long lastMotionTime = 0;
unsigned long lastAutoTime = 0;
bool autoMode = true;

void WIFIConnect() {
  Serial.println("Đang kết nối tới WiFi: Wokwi-GUEST");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi đã kết nối, IP: ");
  Serial.println(WiFi.localIP());
}

void MQTT_Reconnect() {
  while (!client.connected()) {
    if (client.connect(MQTT_ID)) {
      Serial.println("Đã kết nối MQTT");
      client.subscribe(topicKeypadStatus);
      client.subscribe(topicDoorStatus);
    } else {
      delay(5000);
    }
  }
}

void sendMQTT(const char* topic, String payload) {
  client.publish(topic, payload.c_str());
}

void handleKeypadInput() {
  char key = keypad.getKey();
  if (key) {
    if (key == '#') {
      if (enteredPassword == correctPassword) {
        digitalWrite(LED_MOCUA, HIGH);
        sendMQTT(topicKeypadStatus, "Mật khẩu đúng, cửa đã mở");
      } else {
        failCount++;
        if (failCount >= maxFail) {
          sendMQTT(topicKeypadStatus, "Quá nhiều lần nhập sai, hệ thống bị khóa");
          delay(30000);
        }
        digitalWrite(LED_CANHBAO, HIGH);
        delay(500);
        digitalWrite(LED_CANHBAO, LOW);
      }
      enteredPassword = ""; // Đặt lại mật khẩu
    } else if (key == '*') {
      enteredPassword = ""; // Xóa đầu vào
    } else {
      enteredPassword += key;
    }
  }
}

void handleTemperatureHumidity() {
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Không thể đọc cảm biến DHT!");
    return;
  }

  lcd.setCursor(0, 0);
  lcd.print("Nhiet do: ");
  lcd.print(temperature);
  lcd.print(" C");
  lcd.setCursor(0, 1);
  lcd.print("Do am: ");
  lcd.print(humidity);
  lcd.print(" %");

  String tempHumPayload = "{";
  tempHumPayload += "\"temperature\": ";
  tempHumPayload += temperature;
  tempHumPayload += ", \"humidity\": ";
  tempHumPayload += humidity;
  tempHumPayload += "}";

  sendMQTT(topicTempHumidity, tempHumPayload);

  if (temperature < tempThresholdLow) {
    digitalWrite(LED_LOSUOI, HIGH);
    lcd.setCursor(0, 2);
    lcd.print("Bat lo suoi  ");
  } else if (temperature > tempThresholdHigh) {
    digitalWrite(LED_DIEUHOA, HIGH);
    lcd.setCursor(0, 2);
    lcd.print("Bat dieu hoa ");
  } else {
    digitalWrite(LED_LOSUOI, LOW);
    digitalWrite(LED_DIEUHOA, LOW);
    lcd.setCursor(0, 2);
    lcd.print("Nhiet do binh thuong ");
  }
}

void handleLight() {
  int lightValue = analogRead(LDR_PIN);
  if (lightValue > lightThreshold) {
    digitalWrite(LED_REM, HIGH);
    sendMQTT(topicLightStatus, "Ánh sáng cao, rèm đã đóng");
  } else {
    digitalWrite(LED_REM, LOW);
    sendMQTT(topicLightStatus, "Ánh sáng thấp, rèm đã mở");
  }
}

void handleMotion() {
  bool motionDetected = digitalRead(PIR_PIN);
  int lightValue = analogRead(LDR_PIN);

  if (motionDetected && lightValue < lightThreshold) {
    digitalWrite(LED_DEN, HIGH);
    lastMotionTime = millis();
    sendMQTT(topicMotionStatus, "Phát hiện chuyển động, bật đèn");
  }

  if (millis() - lastMotionTime > timeoutLight) {
    digitalWrite(LED_DEN, LOW);
    sendMQTT(topicMotionStatus, "Không có chuyển động, tắt đèn");
  }
}

void setup() {
  Serial.begin(115200);
  WIFIConnect();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback([](char* topic, byte* payload, unsigned int length) {
    Serial.print("Tin nhắn nhận được trên chủ đề: ");
    Serial.println(topic);
    for (int i = 0; i < length; i++) {
      Serial.print((char)payload[i]);
    }
    Serial.println();
  });

  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
  dht.begin();
  lcd.init();
  lcd.backlight();

  pinMode(LDR_PIN, INPUT);
  pinMode(PIR_PIN, INPUT);
  pinMode(LED_LOSUOI, OUTPUT);
  pinMode(LED_DIEUHOA, OUTPUT);
  pinMode(LED_REM, OUTPUT);
  pinMode(LED_MOCUA, OUTPUT);
  pinMode(LED_CANHBAO, OUTPUT);
  pinMode(LED_DEN, OUTPUT);

  digitalWrite(LED_LOSUOI, LOW);
  digitalWrite(LED_DIEUHOA, LOW);
  digitalWrite(LED_REM, LOW);
  digitalWrite(LED_MOCUA, LOW);
  digitalWrite(LED_CANHBAO, LOW);
  digitalWrite(LED_DEN, LOW);
}

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

  handleKeypadInput();
  handleTemperatureHumidity();
  handleLight();
  handleMotion();
  delay(1000);
}