#include <Adafruit_NeoPixel.h>

const int redPin = 4;
const int greenPin = 5;
const int bluePin = 13;
const int whitePin = 14;
const int btnPin = 18;

#define PIN_WS2812B 27
#define NUM_PIXELS 68

Adafruit_NeoPixel ws2812b(NUM_PIXELS, PIN_WS2812B, NEO_GRB + NEO_KHZ800);

String inputCommand = "";
String inputColor = "";

int buttonState = 0;
int lastButtonState = LOW;

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;

void setup() {
  ws2812b.begin();
  Serial.begin(9600);

  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(whitePin, OUTPUT);
  pinMode(btnPin, INPUT);

  analogWrite(redPin, 0);
  analogWrite(greenPin, 0);
  analogWrite(bluePin, 0);
  analogWrite(whitePin, 0);
}

void loop() {
  // Check if there is serial data available
  if (Serial.available() > 0) {
    char receivedChar = Serial.read();
    
    // Check if the received character is not a newline character
    if (receivedChar != ';') {
      inputCommand += receivedChar;
    } else {
      // A newline character indicates the end of the command
      if (inputCommand.startsWith("SET_STRIP_COLOR:")) {

        inputColor = inputCommand.substring(16); // Extract the color value after ":"
        setStripColor(inputColor);
      } else if (inputCommand.startsWith("SET_LIGHT:")) {
        int brightnessValue = inputCommand.substring(10).toInt();
        setLight(brightnessValue);
      } else if (inputCommand.startsWith("SET_LED:")) {
        // Command format: SET_LED:index,R,G,B (e.g., SET_LED:5,255,0,0 for setting LED #5 to red)
        setIndividualLED(inputCommand);
      } else if (inputCommand.startsWith("SET_LED_COLOR:")) {
        // Command format: SET_LED:index,R,G,B (e.g., SET_LED:5,255,0,0 for setting LED #5 to red)
        setLedColor(inputCommand);
      } else if (inputCommand.startsWith("SET_LED_OFF")) {
        // Command format: SET_LED:index,R,G,B (e.g., SET_LED:5,255,0,0 for setting LED #5 to red)
        ws2812b.clear();
        ws2812b.show();
      }
      inputCommand = ""; // Clear the inputCommand string
      inputColor = "";   // Clear the inputColor string
    }
  }

  int reading = digitalRead(btnPin);

  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        Serial.write("1");
      }
    }
  }

  lastButtonState = reading;
}

void setLight(int brightnessValue) {
  // Set the separate light brightness between 0 and 255
  analogWrite(whitePin, constrain(brightnessValue, 0, 255));
}

void setStripColor(String colorString) {
  // Parse the colorString in the format "R,G,B" where R, G, and B are integer
  int commaIndex = colorString.indexOf(',');
  if (commaIndex >= 0) {
    String redStr = colorString.substring(0, commaIndex);
    colorString = colorString.substring(commaIndex + 1);
    commaIndex = colorString.indexOf(',');
    if (commaIndex >= 0) {
      String greenStr = colorString.substring(0, commaIndex);
      String blueStr = colorString.substring(commaIndex + 1);
      
      // Convert the string values to integers
      int redValue = redStr.toInt();
      int greenValue = greenStr.toInt();
      int blueValue = blueStr.toInt();
      
      // Set the RGB LED color based on the parsed values
      analogWrite(redPin, redValue);
      analogWrite(greenPin, greenValue);
      analogWrite(bluePin, blueValue);
    }
  }
}

void setIndividualLED(String command) {
  // Command format: SET_LED:index,R,G,B
  int firstComma = command.indexOf(',');
  int secondComma = command.indexOf(',', firstComma + 1);
  int thirdComma = command.indexOf(',', secondComma + 1);
  
  if (firstComma != -1 && secondComma != -1 && thirdComma != -1) {
    int index = command.substring(8, firstComma).toInt(); // Extract the LED index
    int red = command.substring(firstComma + 1, secondComma).toInt(); // Extract the red value
    int green = command.substring(secondComma + 1, thirdComma).toInt(); // Extract the green value
    int blue = command.substring(thirdComma + 1).toInt(); // Extract the blue value
    
    // Check if the index is within bounds
    if (index >= 0 && index < NUM_PIXELS) {
      ws2812b.setPixelColor(index, ws2812b.Color(red, green, blue));
      ws2812b.show();
    }
  }
}

void setLedColor(String colorString) {
  // Parse the colorString in the format "R,G,B" where R, G, and B are integer
  int commaIndex = colorString.indexOf(',');
  if (commaIndex >= 0) {
    String redStr = colorString.substring(0, commaIndex);
    colorString = colorString.substring(commaIndex + 1);
    commaIndex = colorString.indexOf(',');
    if (commaIndex >= 0) {
      String greenStr = colorString.substring(0, commaIndex);
      String blueStr = colorString.substring(commaIndex + 1);
      
      // Convert the string values to integers
      int redValue = redStr.toInt();
      int greenValue = greenStr.toInt();
      int blueValue = blueStr.toInt();
      
      // Set the RGB LED color based on the parsed values
      ws2812b.fill(ws2812b.Color(redValue, greenValue, blueValue));
      ws2812b.show();
    }
  }
}
