#include <time.h>
// Define globals
const float VCC = 3.3; // ESP32 supply voltage
const int ADC_MAX = 4095; // 12-bit ADC resolution
// Thermal sensor variables
const float THERM_R0 = 78000.0; // Thermistor resistance at T0 (e.g., 10kΩ)
const float THERM_T = 298.15; // T0 in Kelvin (25°C + 273.15)
const float THERM_B_VALUE = 4100.0; // Thermistor's Beta value (from datasheet)
const float THERM_SERIES_RESISTOR = 50000; // Fixed resistor value
//
const int PIN_THERM = 34; // ADC pin for thermal sensor/diode / analog input
const int PIN_MOISTURE = 35; // ADC pin for moisture sensor / analog input
const int PIN_PUMP = 25; // water pump / digital output
const int PIN_ESTUFA = 23;
const int PIN_LED = 27;
const int PIN_FAN = 26;
//
int ct = 0; // current time in seconds
//int dct = 0;
int ctDay = 3600*24; // seconds of day
int curDay = 0; // 0 = day1, 1=day2... until 6=day7 and repeat to 0
int cntDay = 0, chkDay=0;
int delayValue = 50; // sleep of main loop 20-1000ms
// statistic counting variables
int cnt = 0;
int cnt_delay = 0;
int cnt_loop = 0;
int pos=0;
//
int cntFailTemp = 0;
int cntOkTemp = 0;
//
int heat_start = false;
int heat_done = false;
int heat_count = 0;
int heat_last = 0; // ct
//
int fan_start = false;
int fan_done = false;
int fan_count = 0;
int fan_last = 0;
//
time_t currentTime;
struct tm timeinfo;

//
struct FanRun {
 int timeON = 0;
 int timeOFF = 0;
    int ct_start = -1;
    //bool start = false;
    //bool done = false;
    //int count = 0;
};
struct FanRun afr[10];

//
struct Days {
  int dayHours = 18; // hours of light per day
  int dayTemperature = 28; // celsious at day
  int nightTemperature = 25; // celsious at night
};
struct Days timetable[6]; // time table for 7days in a week
//--
//
void get_moisture() {
  int val = analogRead(PIN_MOISTURE);
  Serial.print("Moisture val: ");
  Serial.println(val);
}
//
float get_thermal() {
 Serial.println("get_thermal() START.");
  int val = analogRead(PIN_THERM);
  
  // 1. Calculate Voltage at ADC Pin (Vout)
  float vout = (float)val * (VCC / ADC_MAX);

  // 2. Calculate Thermistor Resistance (Rth) using Voltage Divider
  // Rth = R_series * (Vout / (VCC - Vout))
  float r_th = THERM_SERIES_RESISTOR * (vout / (VCC - vout));
  
  // 3. Calculate Temperature (Kelvin) using Beta Equation
  // 1/T = 1/T0 + (1/B) * ln(Rth/R0)
  float temp_kelvin = 1.0 / ((1.0 / THERM_T) - (1.0 / THERM_B_VALUE) * log(r_th / THERM_R0));

  // 4. Convert Kelvin to Celsius
  float temp_celsius = temp_kelvin - 273.15;
  char debug[256];
  sprintf(debug,"DEBUG get_thermal() ADC: %i, vout: %.1f, rth: %.1f, tk: %.1f tc: %.1f",val, vout, r_th, temp_kelvin, temp_celsius);
  Serial.println(debug);
  return temp_celsius;
}

//
void fan_on(int timeON, int timeOFF) {
 Serial.println("fan_on() START.");
  //
  if( fan_count==0 ) {
 // Turn fan on
 Serial.println("Turn fan on for Xsec");
 fan_count = ct+timeON;
 fan_start = true;
 fan_done = false;
 digitalWrite(PIN_FAN,LOW);
  }
  else if( fan_count < 0 ) {
 Serial.println("Waiting for fan...");
 if( cnt_delay>=1000) fan_count++;
  }
  else if( fan_count > ct ) {
 Serial.println("Waiting for fan to turn it off...");
  }
  else if( fan_count <= ct && fan_done==false ) {
 Serial.println("Turning off fan...");
 fan_off();
  }
  else if( ct >= fan_count ) {
 // Turn fan off
 Serial.println("Setting Turn fan off for Xsec");
 fan_count = timeOFF;
  }
}
//
void fan_off() {
 Serial.println("fan_off() START.");
 fan_done = true;
 fan_start = false;
 fan_count = 0;
 fan_last = ct;
 digitalWrite(PIN_FAN,HIGH);
}

//
void heat_on(int timeON, int timeOFF) {
 Serial.println("heat_on() START.");
  //
  if( heat_count==0 ) {
 // Turn fan on
 Serial.println("Turn heat on for Xsec");
 heat_count = ct+timeON;
 heat_start = true;
 heat_done = false;
 digitalWrite(PIN_ESTUFA,LOW);
  }
  else if( heat_count < 0 ) {
 Serial.println("Waiting for heat...");
 if( cnt_delay>=1000) heat_count++;
  }
  else if( heat_count > ct ) {
 Serial.println("Waiting for heat to turn it off...");
  }
  else if( heat_count <= ct && heat_done==false ) {
   Serial.println("Turning off heat...");
   heat_off();
  }
  else if( ct >= heat_count ) {
 // Turn heat off
 Serial.println("Setting Turn heat off for Xsec");
 heat_count = timeOFF;
  }
}
//
void heat_off() {
 Serial.println("heat_off() START.");
 heat_done = true;
 heat_start = false;
 heat_count = 0;
 heat_last = ct;
 digitalWrite(PIN_ESTUFA,HIGH);
}
//
void heating_on() {
 Serial.println("heating_on() START.");
 heat_on(100,-100);
 if( (fan_last+3)<ct ) {
  fan_on(2,-3);
 }
}
//
void heating_off() {
 Serial.println("heating_off() START.");
 if( !heat_done ) {
  heat_off();
 }
 if( !fan_done ) {
  fan_off();
 }
}
//
void light_on() {
 Serial.println("light_on() START.");
 digitalWrite(PIN_LED,LOW);
}
//
void light_off() {
 Serial.println("light_off() START.");
 digitalWrite(PIN_LED,HIGH);
}
//
void set_time(time_t configTime) {
 //
 //dct = (int)configTime;
 // Convert struct tm to time_t
 time_t epoch = configTime;
 // Create struct timeval from time_t
 struct timeval tv;
 tv.tv_sec = epoch;
 tv.tv_usec = 0; // Microseconds (0-999999)
 // Set the system time
 int result = settimeofday(&tv, NULL);
 if (result == 0) {
 Serial.println("Time set successfully");
 } else {
 Serial.println("Failed to set time");
 }
}

// Configure setup
void setup() {
  delay(500);
  //
  Serial.begin(115200);
  //--
  //
  pinMode(PIN_FAN,OUTPUT); // led
  digitalWrite(PIN_FAN,HIGH); // off

  // Light LED
  pinMode(PIN_LED,OUTPUT);
  digitalWrite(PIN_LED,HIGH);

  // WATER PUMP - off
  pinMode(PIN_PUMP,OUTPUT);
  digitalWrite(PIN_PUMP,HIGH);

  // ESTUFA - HEATER
  pinMode(PIN_ESTUFA,OUTPUT);
  digitalWrite(PIN_ESTUFA,HIGH); // HIGH = Off for Relay
  //digitalWrite(PIN_ESTUFA,LOW);
  // MOISTURE SensOr - problem!
  /*analogWrite(32,500);
  pinMode(32,OUTPUT); // led
  digitalWrite(32,LOW); // off*/

  // Define timetable for a week
  timetable[0] = (Days){18,28,25};
  timetable[1] = (Days){18,28,25};
  timetable[2] = (Days){18,28,25};
  timetable[3] = (Days){18,28,25};
  timetable[4] = (Days){18,28,25};
  timetable[5] = (Days){18,28,25};
  timetable[6] = (Days){18,28,25};
  // start_ts, start, done
  afr[0] = (FanRun){10, false, false};
  set_time(6780);
}



// Program loop
void loop() {
 // Get current time as seconds since the Unix epoch (January 1, 1970)
 //time_t currentTime = time(nullptr); // Note: nullptr is valid in Arduino for C++11+
 currentTime = time(&currentTime); // Note: nullptr is valid in Arduino for C++11+
 ct = currentTime;
 cntDay = (ct/ctDay);
 // reset current time to zerro after day 7 is finished
 if( curDay>6 ) {
  Serial.println("Weekend is over. Roots should be out...");
  curDay = 0;
 }
 if( chkDay!=cntDay) {
  chkDay=cntDay;
  curDay++;
  //dct=0;
 }
 //
 Days ttable = timetable[curDay];
 // Print by second
 if( cnt_delay==1000 ) {
  // calculate secunds of light per day depend on dayHours
  int sol = (60*60)*ttable.dayHours; // 60sec * 60sec = 1hour of sec * dayHours
  int dtemp = ttable.dayTemperature;
  int ntemp = ttable.nightTemperature;
  
  // day ct. Useful for days 2-7
  //int dct = (curDay * ctDay)-ct;
  int dct = ct;
  if( cntDay>0 ) {
   dct = -(((cntDay * ctDay)-ct));
  }
  // Convert to local time
  struct tm *timeInfo = localtime(&currentTime);
  
  // Format the timestamp
  char buffer[64];
  strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeInfo);
  
  Serial.println(buffer);
  Serial.println(currentTime);
  
  //
  float temp = get_thermal();
  
  // DEBUG
  char tmp[256];
  sprintf(tmp,"Loop cft: %i, cd: %i/%i, sol: %i, t: %.1f/%i/%i, dct: %i, ct: %i, pos: %i, cnt: %i, cnt_loop: %i", cntFailTemp, curDay, cntDay, sol, temp,dtemp,ntemp, dct, ct, pos, cnt, cnt_loop);
  Serial.println(tmp);
  
  // CHECK SOL
  if( dct<sol ) { // Should be LIGHT
   //
   light_on();
   //
   if( temp < dtemp ) { // START HEAT
    if( cntFailTemp>= 5 ) {
     // start heat
     cntOkTemp=0;
     heating_on();
    }
    cntFailTemp++;
   }
   else {
    if( cntOkTemp >= 5 ) {
     // stop heat
     cntFailTemp = 0;
     if( !heat_done ) {
      heating_off();
     }
    }
    else if( cntFailTemp>0 ) {
     heating_on();
    }
    //}
    cntOkTemp++;
   }
  }
  else { // Should be NIGHT
   //
   light_off();
   //
   if( temp < ntemp ) { // START HEAT
    if( cntFailTemp>= 5 ) {
     // start heat
     cntOkTemp=0;
     heating_on();
    }
    cntFailTemp++;
   }
   else {
    if( cntOkTemp >= 5 ) {
     // stop heat
     cntFailTemp = 0;
     if( !heat_done ) {
      heating_off();
     }
    }
    else if( cntFailTemp>0 ) {
     heating_on();
    }
    //}
    cntOkTemp++;
   }
  }
 }
  
 // Reset cnd on 25 or X
 if( cnt==(1000/delayValue) ) {
  pos+=1;
  cnt=0;
  cnt_loop=0;
 }
 // Count cnt every second. Important variables: cnt_delay and delayValue
 if( cnt_delay>= 1000 ) {
  cnt_delay = 0;
  cnt += 1;
  //dct++;
 }
 //
 cnt_delay += delayValue;
 cnt_loop+=1;
 //
 delay(delayValue);
}