#define IO_USERNAME    "Your IO username"
#define IO_KEY         "Your IO key"

/******************************* WIFI Configuration **************************************/

#define WIFI_SSID       "Your wifi ssid"
#define WIFI_PASS       "Your wifi pass"

#include "AdafruitIO_WiFi.h"
AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);


/************************ Main Program Starts Here *******************************/
#include <ESP8266WiFi.h>
#include <Adafruit_MQTT.h>
#include <ArduinoHttpClient.h>
#include <Adafruit_NeoPixel.h>
#include <AdafruitIO.h>
#include <AdafruitIO_WiFi.h>

#define BUTTON_PIN 4
#define PIXELS_PIN 15
#define NUM_LEDS 16
#define BRIGHTNESS 50

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIXELS_PIN, NEO_GRBW + NEO_KHZ800);

// Number of initial red and blue lights
int redLights = 0;
int blueLights = 0;

// Red light and blue light timer
unsigned long redTimer = 0;
unsigned long blueTimer = 0;

// set up the 'command' and 'command2' feeds
AdafruitIO_Feed *command = io.feed("command");
AdafruitIO_Feed *command2 = io.feed("command2");

void setup() {
  // set button pin as an input
  pinMode(BUTTON_PIN, INPUT_PULLUP);

  strip.setBrightness(BRIGHTNESS);
  strip.begin();
  strip.show();

  // start the serial connection
  Serial.begin(115200);

  // connect to io.adafruit.com
  Serial.print("Connecting to Adafruit IO");
  io.connect();

  // set up message handlers for the 'command' and 'command2' feeds.
  command->onMessage(handleCommand);
  command2->onMessage(handleCommand2);

  // wait for a connection
  while (io.status() < AIO_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  // we are connected
  Serial.println();
  Serial.println(io.statusText());
}

void loop() {
  // io.run() is required for all sketches.
  // it should always be present at the top of your loop
  // function. it keeps the client connected to
  // io.adafruit.com, and processes any incoming data.
  io.run();

  // Update the status of red and blue lights
  updateLights();

  // grab the current state of the button.
  // we have to flip the logic because we are
  // using INPUT_PULLUP.
  int buttonState = digitalRead(BUTTON_PIN);

  // If the physical button is pressed
  if (buttonState == LOW) {
    // Execute the logic of the master switch
    toggleLights();
    delay(500); 
  }
}

void handleCommand(AdafruitIO_Data *data) {
  // Process the message of command
  int commandValue = data->toInt();
  if (commandValue == 1) {
    // If signal 1 is received, the red light increases by 2
    redLights += 2;
    updateLights();
  }
}

void handleCommand2(AdafruitIO_Data *data) {
  // Process the message of command2
  int command2Value = data->toInt();
  if (command2Value == 1) {
    // If signal 1 is received, the blue light increases by 4
    blueLights += 4;
    updateLights();
  }
}

void toggleLights() {
  // Switch the status of all red and blue lights
  redLights = (redLights == 0) ? 8 : 0;
  blueLights = (blueLights == 0) ? 8 : 0;
  Serial.println("Toggled lights");  
  updateLights();  
}

void updateLights() {
  // Get current time
  unsigned long currentTime = millis();

  // The red light goes down every two hours
  if (currentTime - redTimer >= 2 * 60 * 60 * 1000) {
    redTimer = currentTime;
    if (redLights > 0) {
      // Let the red light to be turned off flash only five times before turning it off
      blinkOffLights(redLights - 1, 5, strip.Color(255, 0, 0, 0));
      redLights = max(0, redLights - 1);
    }
  }

  // The blue light goes down every eight minutes
  if (currentTime - blueTimer >= 8 * 60 * 1000) {
    blueTimer = currentTime;
    if (blueLights > 0) {
      // Let the blue light to be extinguished flash only five times before it is extinguished
      blinkOffLights(7 + blueLights, 5, strip.Color(0, 0, 255, 0));
      blueLights = max(0, blueLights - 1);
    }
  }

  for (int i = 0; i < 8; i++) {
    // Set the color of the red light
    uint32_t redColor = (i < redLights) ? strip.Color(255, 0, 0, 0) : strip.Color(0, 0, 0, 0);
    strip.setPixelColor(i, redColor);
  }

  for (int i = 8; i < 16; i++) {
    // Set the color of the blue light
    uint32_t blueColor = (i - 8 < blueLights) ? strip.Color(0, 0, 255, 0) : strip.Color(0, 0, 0, 0);
    strip.setPixelColor(i, blueColor);
  }

  strip.show();
}

void blinkOffLights(int targetIdx, int numBlinks, uint32_t color) {
  for (int blinkCount = 0; blinkCount < numBlinks; blinkCount++) {
    // blink
    strip.setPixelColor(targetIdx, color);
    strip.show();
    delay(500);

    // Off
    strip.setPixelColor(targetIdx, strip.Color(0, 0, 0, 0));
    strip.show();
    delay(500);
  }
}
