#include <Servo.h>
#include <EEPROM.h>
#include <stdio.h>
#include <avr/sleep.h>

// === Pin assignments ===
const int servoPin = 13;
const int uvLedPin = 12;             // UV light (purple)
const int statusLED = 11;            // Blue LED = temp too cold/hot
const int lightStatusLED = 10;       // Yellow LED = light too bright
const int batteryStatusLED = 9;      // Red LED = battery low indicator

// === User-adjustable parameters ===
const int flailRPM = 30;
const unsigned long servoOnMs = 1000;
const unsigned long servoOffMs = 1000;
const float dutyPauseSec = 3.0;

const float lightThreshold = 500.0;
const float minTempF = 50.0;
const float maxTempF = 95.0;
const float lowBatteryCutoff = 6.5;

const unsigned long logInterval = 10000; // iterate conditions every 10s
const int intervalSec = logInterval / 1000;

Servo flailServo;

unsigned long lastLogTime = 0;
unsigned long lastBlinkTime = 0;
bool blinkState = false;

unsigned long currentTime;
bool controlFlail = false;

int flailCycleCount = 0;
bool batteryOK = true;
bool uvOn = false;
int bootCount = 0;

void goToSleep() {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_cpu();
  sleep_disable();
}

void setup() {
  Serial.begin(9600);
  flailServo.attach(servoPin);
  pinMode(uvLedPin, OUTPUT);
  pinMode(statusLED, OUTPUT);
  pinMode(lightStatusLED, OUTPUT);
  pinMode(batteryStatusLED, OUTPUT);

  bootCount = EEPROM.read(0);
  if (bootCount == 255) bootCount = 0;
  bootCount++;
  EEPROM.write(0, bootCount);

  Serial.println("Iteration,Flail,Light,Temp,Battery,SleepState,Day,Time,IntervalSec,JitterSec,DurationSec,TempF,LightLux,FlailCycles,ServoRPM,DutyOn,DutyPause,BootCount");
}

void loop() {
  currentTime = millis();
  static int iteration = 1;
  static float temperatureF = 60;
  static float lightLux = 400;
  static float batteryV = 7.0;
  static int step = 0;
  static bool tempTooCold, tempTooHot, lightTooBright;

  if (currentTime - lastBlinkTime >= 500) {
    blinkState = !blinkState;
    lastBlinkTime = currentTime;
  }

  bool doLog = false;
  if (currentTime - lastLogTime >= logInterval) {
    lastLogTime = currentTime;
    doLog = true;

    step = (step + 1) % 8;
    switch (step) {
      case 0: temperatureF = 40; lightLux = 300; batteryV = 7.5; break;
      case 1: temperatureF = 60; lightLux = 600; batteryV = 7.5; break;
      case 2: temperatureF = 100; lightLux = 300; batteryV = 7.5; break;
      case 3: temperatureF = 60; lightLux = 300; batteryV = 6.0; break;
      case 4: temperatureF = 60; lightLux = 300; batteryV = 7.5; break;
      case 5: temperatureF = 40; lightLux = 600; batteryV = 7.5; break;
      case 6: temperatureF = 100; lightLux = 600; batteryV = 7.5; break;
      case 7: temperatureF = 100; lightLux = 600; batteryV = 6.0; break;
    }

    tempTooCold = (temperatureF <= minTempF);
    tempTooHot = (temperatureF >= maxTempF);
    lightTooBright = (lightLux >= lightThreshold);
    batteryOK = (batteryV >= lowBatteryCutoff);

    controlFlail = batteryOK && !tempTooCold && !tempTooHot && !lightTooBright;
  }

  if (controlFlail) {
    if (!uvOn) {
      digitalWrite(uvLedPin, HIGH);
      uvOn = true;
    }

    // ✅ Turn off red battery LED during active flailing
    digitalWrite(batteryStatusLED, LOW);

    unsigned long startFlailTime = millis();
    while (millis() - startFlailTime < logInterval) {
      flailServo.write(180);
      delay(servoOnMs);
      flailServo.write(0);
      delay(servoOffMs);
      flailCycleCount++;
    }
  } else {
    if (uvOn) {
      digitalWrite(uvLedPin, LOW);
      uvOn = false;
    }
    flailServo.write(0);
  }

  // LED indicators
  digitalWrite(statusLED, tempTooHot ? HIGH : (tempTooCold ? blinkState : LOW));
  digitalWrite(lightStatusLED, lightTooBright ? blinkState : LOW);
  if (!controlFlail) {
    digitalWrite(batteryStatusLED, batteryOK ? LOW : blinkState);
  }

  if (doLog) {
    unsigned long totalSeconds = currentTime / 1000;
    int hours = (totalSeconds / 3600) % 24;
    int minutes = (totalSeconds / 60) % 60;
    int seconds = totalSeconds % 60;

    char timeStr[9];
    sprintf(timeStr, "%02d:%02d:%02d", hours, minutes, seconds);

    String lightStr = lightTooBright ? "light_detected" : "dark";
    String tempStr = tempTooCold ? "temp_cold" : (tempTooHot ? "temp_hot" : "temp_inrange");
    String batteryStr = batteryOK ? "battery_okay" : "battery_low";
    String flailStr = controlFlail ? "active" : "idle";
    String sleepStr = controlFlail ? "awake" : "sleep";

    Serial.print(iteration++); Serial.print(",");
    Serial.print(flailStr); Serial.print(",");
    Serial.print(lightStr); Serial.print(",");
    Serial.print(tempStr); Serial.print(",");
    Serial.print(batteryStr); Serial.print(",");
    Serial.print(sleepStr); Serial.print(",");
    Serial.print(0); Serial.print(",");
    Serial.print(timeStr); Serial.print(",");
    Serial.print(intervalSec); Serial.print(",");
    Serial.print("0.00"); Serial.print(",");
    Serial.print(intervalSec); Serial.print(",");
    Serial.print((int)temperatureF); Serial.print(",");
    Serial.print((int)lightLux); Serial.print(",");
    Serial.print(flailCycleCount); Serial.print(",");
    Serial.print(controlFlail ? String(flailRPM) : "NA"); Serial.print(",");
    Serial.print(controlFlail ? String(servoOnMs / 1000.0, 1) + "s" : "NA"); Serial.print(",");
    Serial.print(dutyPauseSec, 1); Serial.print("s,");
    Serial.print(bootCount); Serial.println();

    flailCycleCount = 0;

    if (!controlFlail) {
      delay(50);  // Allow Serial to flush
      goToSleep();
    }
  }
}