#include <Wire.h>
#include "Adafruit_SHT31.h"
#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include <RTClib.h>

// ================= WIFI =================
#define WIFI_SSID "Toge"
#define WIFI_PASSWORD "123123123"

// ================= FIREBASE =================
#define DATABASE_URL "https://smarttoge-default-rtdb.firebaseio.com/"
#define DATABASE_SECRET "0CWsHxiRJar3qXSx4uGX385rf0VAnpKKOhQ1wbok"

// ================= PIN =================
#define RELAY_PIN 5

// ================= OBJECT =================
Adafruit_SHT31 sht31 = Adafruit_SHT31();
RTC_DS3231 rtc;

FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;

FirebaseJson json;
FirebaseJsonData result;

// ================= VAR GLOBAL =================
bool relayOn = false;
bool pumpRunning = false;
bool pumpManual = false;
bool humidityNotifSent = false;
bool wateringDoneNotifSent = false;
String activeScheduleKey = "";


// TIMER
unsigned long lastSensor = 0;
unsigned long lastFirebase = 0;
unsigned long lastSchedule = 0;
unsigned long lastManual = 0;

// DATA GLOBAL
float suhu = 0;
float kelembaban = 0;

String rtcDate = "";
String rtcTime = "";

// ================= SET RTC DARI SERIAL =================
void setRTCFromSerial() {

  if (Serial.available()) {

    String input = Serial.readStringUntil('\n');
    input.trim();

    int year, month, day, hour, minute, second;

    if (sscanf(input.c_str(), "%d-%d-%d %d:%d:%d",
               &year, &month, &day,
               &hour, &minute, &second) == 6) {

      rtc.adjust(DateTime(year, month, day, hour, minute, second));

      Serial.println("RTC berhasil di-set!");
    } else {
      Serial.println("Format salah! Gunakan: YYYY-MM-DD HH:MM:SS");
    }
  }
}

// ================= SETUP =================
void setup() {

  Serial.begin(115200);

  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, HIGH);

  Wire.begin(21, 22);

  if (!sht31.begin(0x44)) {
    Serial.println("Sensor tidak ditemukan!");
    while (1);
  }

  if (!rtc.begin()) {
    Serial.println("RTC tidak ditemukan!");
    while (1);
  }

  // Set otomatis kalau RTC kehilangan daya
  if (rtc.lostPower()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  Serial.println("Masukkan waktu RTC format:");
  Serial.println("YYYY-MM-DD HH:MM:SS");

  // ================= WIFI =================
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting WiFi");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("\nWiFi Connected");

  config.database_url = DATABASE_URL;
  config.signer.tokens.legacy_token = DATABASE_SECRET;

  Firebase.begin(&config, &auth);
  Firebase.reconnectWiFi(true);
}

// ================= LOOP =================
void loop() {

  setRTCFromSerial(); // 🔥 input waktu dari serial

  unsigned long nowMillis = millis();

  // ================= SENSOR =================
  if (nowMillis - lastSensor > 2000) {
    lastSensor = nowMillis;

    suhu = sht31.readTemperature();
    kelembaban = sht31.readHumidity();

    DateTime now = rtc.now();

    char tgl[11];
    sprintf(tgl, "%02d-%02d-%04d", now.day(), now.month(), now.year());
    rtcDate = String(tgl);

    char jam[9];
    sprintf(jam, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
    rtcTime = String(jam);

    Serial.println("Sensor Update");
  }

  // ================= MANUAL =================
  if (nowMillis - lastManual > 2000) {
    lastManual = nowMillis;

    if (Firebase.RTDB.getBool(&fbdo, "/pump/status")) {
      pumpManual = fbdo.boolData();
    }
  }

  // ================= SCHEDULE =================
  if (nowMillis - lastSchedule > 15000) {
    lastSchedule = nowMillis;

    relayOn = false;

    if (Firebase.RTDB.getJSON(&fbdo, "/schedules")) {

      json = fbdo.jsonObject();
      size_t len = json.iteratorBegin();

      String key, value;
      int type;

      for (size_t i = 0; i < len; i++) {

        json.iteratorGet(i, type, key, value);

        String scheduleTime, scheduleDate, scheduleStatus;

        if (json.get(result, key + "/time"))
          scheduleTime = result.to<String>();

        if (json.get(result, key + "/date"))
          scheduleDate = result.to<String>();

        if (json.get(result, key + "/status"))
          scheduleStatus = result.to<String>();

        int schHour = 0, schMinute = 0;
        sscanf(scheduleTime.c_str(), "%d:%d", &schHour, &schMinute);

        DateTime now = rtc.now();
        int hour = now.hour();
        int minute = now.minute();

if (rtcDate == scheduleDate &&
    (hour > schHour || (hour == schHour && minute >= schMinute)) &&
    scheduleStatus == "idle" &&
    kelembaban < 85) {

  relayOn = true;

  activeScheduleKey = key;

  Firebase.RTDB.setString(
      &fbdo,
      "/schedules/" + key + "/status",
      "watering");

  Serial.println("TRIGGER SCHEDULE");
}

        else if (scheduleStatus == "watering" && !pumpRunning) {
          Firebase.RTDB.setString(&fbdo,
                                  "/schedules/" + key + "/status",
                                  "done");
        }
      }

      json.iteratorEnd();
    }
  }

  // ================= RELAY =================
  if (pumpManual) {
    digitalWrite(RELAY_PIN, LOW);
  }

else if (relayOn && !pumpRunning) {

  digitalWrite(RELAY_PIN, LOW);
  pumpRunning = true;

  Serial.println("POMPA ON");
}

// ================= AUTO OFF SAAT KELEMBAPAN >= 85 =================
if (pumpRunning && kelembaban >= 85) {

  digitalWrite(RELAY_PIN, HIGH);

  pumpRunning = false;
  relayOn = false;

  Serial.println("POMPA OFF - KELEMBAPAN SUDAH 85%");

  // UPDATE STATUS JADWAL MENJADI DONE
  if (activeScheduleKey != "") {

    Firebase.RTDB.setString(
        &fbdo,
        "/schedules/" + activeScheduleKey + "/status",
        "done");

    activeScheduleKey = "";
  }

  // NOTIFIKASI
  Firebase.RTDB.setString(
      &fbdo,
      "/notification/type",
      "watering_done");

  Firebase.RTDB.setString(
      &fbdo,
      "/notification/message",
      "Penyiraman selesai. Kelembapan telah mencapai 85%");

  Firebase.RTDB.setInt(
      &fbdo,
      "/notification/timestamp",
      millis());

  wateringDoneNotifSent = true;
}

  // ================= DEFAULT OFF =================
  if (!relayOn && !pumpRunning && !pumpManual) {
    digitalWrite(RELAY_PIN, HIGH);
  }

  // ================= FIREBASE UPDATE =================
  if (nowMillis - lastFirebase > 5000) {
    lastFirebase = nowMillis;

    Firebase.RTDB.setFloat(&fbdo, "/sht/temperature", suhu);
    Firebase.RTDB.setFloat(&fbdo, "/sht/humidity", kelembaban);
    Firebase.RTDB.setString(&fbdo, "/sht/time", rtcTime);
    Firebase.RTDB.setString(&fbdo, "/sht/date", rtcDate);

// ================= NOTIFIKASI KELEMBAPAN =================
if (kelembaban < 70) {

  if (!humidityNotifSent) {

    Firebase.RTDB.setString(
        &fbdo,
        "/notification/type",
        "humidity_low");

    Firebase.RTDB.setString(
        &fbdo,
        "/notification/message",
        "Kelembapan rendah, segera lakukan penyiraman");

    Firebase.RTDB.setInt(
        &fbdo,
        "/notification/timestamp",
        millis());

    humidityNotifSent = true;
    wateringDoneNotifSent = false;
  }

} else {

  humidityNotifSent = false;
}

    Serial.println("Firebase Update");
  }
}