#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <Preferences.h>
#include "time.h"

// Hardware Configuration
const int RELAY_PINS[5] = {22, 23, 5, 18, 19}; 
const char* ssid = "XM";
const char* password = "79797979";
const char* apiUrl = "https://hivemq.nongnghiep24h.com/get_schedule.php";

// NTP Time Settings
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 25200; // Adjust for your timezone (e.g., +7 hours = 25200)
const int   daylightOffset_sec = 0;

Preferences prefs;

struct RelaySchedule {
  bool enabled;
  int hour;
  int minute;
  bool days[7]; // 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat
};

RelaySchedule schedules[5];
const char* DAY_NAMES[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

void setup() {
  Serial.begin(115200);
  
  // Initialize Relays
  for(int i=0; i<5; i++) {
    pinMode(RELAY_PINS[i], OUTPUT);
    digitalWrite(RELAY_PINS[i], LOW); // Default off
  }

  // Connect Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) { delay(500); }

  // Init NTP Time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  
  // Load local backups from Preferences
  loadLocalSchedules();
  
  // Fetch latest updates from PHP API
  fetchRemoteSchedules();
}

void loop() {
  static unsigned long lastCheck = 0;
  if (millis() - lastCheck >= 1000) { // Check every second
    lastCheck = millis();
    checkSchedules();
  }
  
  // Fetch new API updates every 30 seconds
  static unsigned long lastApiFetch = 0;
  if (millis() - lastApiFetch >= 30000) {
    lastApiFetch = millis();
    fetchRemoteSchedules();
  }
}

void loadLocalSchedules() {
  prefs.begin("relay_prefs", true);
  for(int i=0; i<5; i++) {
    String prefix = "r" + String(i);
    schedules[i].enabled = prefs.getBool((prefix + "_en").c_str(), false);
    schedules[i].hour = prefs.getInt((prefix + "_h").c_str(), 0);
    schedules[i].minute = prefs.getInt((prefix + "_m").c_str(), 0);
    
    for(int d=0; d<7; d++) {
      String dayKey = prefix + "_d" + String(d);
      schedules[i].days[d] = prefs.getBool(dayKey.c_str(), false);
    }
  }
  prefs.end();
}

void saveLocalSchedule(int index) {
  prefs.begin("relay_prefs", false);
  String prefix = "r" + String(index);
  prefs.putBool((prefix + "_en").c_str(), schedules[index].enabled);
  prefs.putInt((prefix + "_h").c_str(), schedules[index].hour);
  prefs.putInt((prefix + "_m").c_str(), schedules[index].minute);
  
  for(int d=0; d<7; d++) {
    String dayKey = prefix + "_d" + String(d);
    prefs.putBool(dayKey.c_str(), schedules[index].days[d]);
  }
  prefs.end();
}

void fetchRemoteSchedules() {
  if(WiFi.status() != WL_CONNECTED) return;
  
  HTTPClient http;
  http.begin(apiUrl);
  int httpCode = http.GET();
  
  if (httpCode == HTTP_CODE_OK) {
    String payload = http.getString();
    JsonDocument doc;
    deserializeJson(doc, payload);
    JsonArray arr = doc.as<JsonArray>();
    
    for (JsonVariant val : arr) {
      int rNum = val["relay_num"].as<int>() - 1;
      if(rNum >= 0 && rNum < 5) {
        schedules[rNum].enabled = val["is_enabled"].as<int>() == 1;
        
        String tTime = val["target_time"].as<String>(); // "HH:MM:SS"
        schedules[rNum].hour = tTime.substring(0,2).toInt();
        schedules[rNum].minute = tTime.substring(3,5).toInt();
        
        String daysStr = val["days_of_week"].as<String>();
        for(int d=0; d<7; d++) {
          schedules[rNum].days[d] = (daysStr.indexOf(DAY_NAMES[d]) != -1);
        }
        saveLocalSchedule(rNum);
      }
    }
  }
  http.end();
}

void checkSchedules() {
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)) return;

  int currentHour = timeinfo.tm_hour;
  int currentMinute = timeinfo.tm_min;
  int currentSecond = timeinfo.tm_sec;
  int currentWday = timeinfo.tm_wday; // 0=Sun, 1=Mon, ..., 6=Sat

  for(int i=0; i<5; i++) {
    if (schedules[i].enabled && schedules[i].days[currentWday]) {
      // Trigger target event right at the beginning of the target minute
      if (currentHour == schedules[i].hour && currentMinute == schedules[i].minute && currentSecond == 0) {
        digitalWrite(RELAY_PINS[i], HIGH);
        Serial.printf("Relay %d Turned ON\n", i + 1);
      }
    }
  }
}
