#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include <addons/TokenHelper.h>
#include <addons/RTDBHelper.h>

// ================= KONFIGURASI WIFI =================
#define WIFI_SSID     "Waris"
#define WIFI_PASSWORD "bayardulu"

// ================= KONFIGURASI FIREBASE =================
#define DATABASE_URL    "https://sigesit-48741-default-rtdb.firebaseio.com"
#define DATABASE_SECRET "eaUKMEaqkEdhqUfPoMjdkxLkX0ay7R3W7luQIDrQ"

// ================= KONFIGURASI PIN =================
const int SENSOR_PIN = 34;
const int RELAY_PIN  = 25;

// ================= KALIBRASI SENSOR =================
const int SOIL_DRY = 3200;
const int SOIL_WET = 1200;

// ================= FIREBASE OBJECT =================
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;

// ================= VARIABEL KONTROL =================
unsigned long prevMillis = 0;
const long INTERVAL = 3000; // Update setiap 3 detik

bool isManual = false;
int pumpStatus = 0;

// Untuk mendeteksi perubahan status pompa
bool lastPumpState = false;

void setup() {

  Serial.begin(115200);
  delay(1000);

  Serial.println("\n--- SISTEM SIGESIT DIMULAI ---");

  pinMode(SENSOR_PIN, INPUT);
  pinMode(RELAY_PIN, OUTPUT);

  // Relay OFF saat awal
  digitalWrite(RELAY_PIN, HIGH);

  // ================= KONEKSI WIFI =================
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  Serial.print("Menghubungkan ke WiFi: ");
  Serial.println(WIFI_SSID);

  int timeout = 0;

  while (WiFi.status() != WL_CONNECTED && timeout < 20) {

    delay(500);
    Serial.print(".");
    timeout++;
  }

  if (WiFi.status() == WL_CONNECTED) {

    Serial.println("\n[OK] WiFi Terhubung!");
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());

  } else {

    Serial.println("\n[GAGAL] WiFi tidak terhubung!");
  }

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

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

  configTime(0, 0, "pool.ntp.org");

  Serial.println("[OK] Firebase Siap!");
}

void loop() {

  if (Firebase.ready()) {

    // =================================================
    // A. KONTROL RESPONSIVE DARI FIREBASE
    // =================================================

    if (Firebase.RTDB.getBool(&fbdo, "/sensor/is_manual")) {

      isManual = fbdo.to<bool>();
    }

    if (isManual) {

      if (Firebase.RTDB.getInt(&fbdo, "/sensor/pump_status")) {

        pumpStatus = fbdo.to<int>();

        digitalWrite(
          RELAY_PIN,
          (pumpStatus == 1) ? LOW : HIGH
        );
      }
    }

    // =================================================
    // B. PEMBACAAN SENSOR
    // =================================================

    unsigned long currentMillis = millis();

    if (currentMillis - prevMillis >= INTERVAL) {

      prevMillis = currentMillis;

      int nilaiADC = analogRead(SENSOR_PIN);

      int soilPercent = map(
                            nilaiADC,
                            SOIL_DRY,
                            SOIL_WET,
                            0,
                            100
                          );

      soilPercent = constrain(soilPercent, 0, 100);

      // =================================================
      // C. MODE OTOMATIS POMPA
      // =================================================

      if (!isManual) {

        if (soilPercent < 50) {

          digitalWrite(RELAY_PIN, LOW);
          pumpStatus = 1;

        } else if (soilPercent > 56) {

          digitalWrite(RELAY_PIN, HIGH);
          pumpStatus = 0;
        }
      }

      // =================================================
      // D. SERIAL MONITOR
      // =================================================

      Serial.print("Kelembaban: ");
      Serial.print(soilPercent);
      Serial.print("% | ");

      Serial.print("Pompa: ");
      Serial.print(pumpStatus == 1 ? "NYALA" : "MATI");

      Serial.print(" | Mode: ");
      Serial.println(isManual ? "MANUAL" : "OTOMATIS");

      // =================================================
      // E. UPDATE REALTIME KE FIREBASE
      // =================================================

      FirebaseJson json;

      json.set("soil_percent", soilPercent);
      json.set("pump_status", pumpStatus);
      json.set("is_manual", isManual);

      if (!Firebase.RTDB.updateNode(&fbdo, "/sensor", &json)) {

        Serial.print("Gagal Update Firebase: ");
        Serial.println(fbdo.errorReason());
      }

      // =================================================
      // F. RIWAYAT PENYIRAMAN
      // =================================================

      // ================= POMPA MENYALA =================
      if (pumpStatus == 1 && !lastPumpState) {

        FirebaseJson history;

        history.set("timestamp/.sv", "timestamp");
        history.set("value", soilPercent);
        history.set("pump", "Penyiraman Aktif");

        if (Firebase.RTDB.pushJSON(&fbdo, "/history", &history)) {

          Serial.println(">>> Penyiraman Aktif");

        } else {

          Serial.print("Gagal Simpan Riwayat: ");
          Serial.println(fbdo.errorReason());
        }
      }

      // ================= POMPA MATI =================
      if (pumpStatus == 0 && lastPumpState) {

        FirebaseJson history;

        history.set("timestamp/.sv", "timestamp");
        history.set("value", soilPercent);
        history.set("pump", "Penyiraman Selesai");

        if (Firebase.RTDB.pushJSON(&fbdo, "/history", &history)) {

          Serial.println(">>> Penyiraman Selesai");

        } else {

          Serial.print("Gagal Simpan Riwayat: ");
          Serial.println(fbdo.errorReason());
        }
      }

      // Simpan status pompa sebelumnya
      lastPumpState = (pumpStatus == 1);
    }

  } else {

    static unsigned long lastError = 0;

    if (millis() - lastError > 5000) {

      lastError = millis();
      Serial.println("Menunggu Firebase Ready...");
    }
  }

  // =================================================
  // AUTO RECONNECT WIFI
  // =================================================

  if (WiFi.status() != WL_CONNECTED) {

    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  }
}
