#include <Arduino.h>
#include <WiFi.h>
#include <Espalexa.h>

#include <credentials.h>

// prototypes
boolean connectWifi();

//callback functions
void workingLightChanged(EspalexaDevice* dev);
void monitorLightChanged(EspalexaDevice* dev);
void cabinetLightChanged(EspalexaDevice* dev);

boolean wifiConnected = false;

Espalexa espalexa;

const int freq = 5000;
const int resolution = 8;

int redPin1 = 18;
int greenPin1 = 17;
int bluePin1 = 16;

int redPin2 = 22;
int greenPin2 = 21;
int bluePin2 = 23;

int redPin3 = 25;
int greenPin3 = 26;
int bluePin3 = 32;

int redPin4 = 19;
int greenPin4 = 13;
int bluePin4 = 33;

const int redChannel1 = 0;
const int greenChannel1 = 1;
const int blueChannel1 = 2;

const int redChannel2 = 3;
const int greenChannel2 = 4;
const int blueChannel2 = 5;

const int redChannel3 = 6;
const int greenChannel3 = 7;
const int blueChannel3 = 8;

const int redChannel4 = 9;
const int greenChannel4 = 10;
const int blueChannel4 = 11;

// connect to wifi – returns true if successful or false if not
boolean connectWifi(){
  boolean state = true;
  int i = 0;
  
  WiFi.mode(WIFI_STA);
  WiFi.setHostname(WIFI_DEVICE_NAME);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.println("");
  Serial.println("Connecting to WiFi");

  // Wait for connection
  Serial.print("Connecting...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (i > 20){
      state = false; break;
    }
    i++;
  }
  Serial.println("");
  if (state){
    Serial.print("Connected to ");
    Serial.println(WIFI_SSID);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  }
  else {
    Serial.println("Connection failed.");
  }
  return state;
}

int lightDimming(int lightValue, int lightBrigtness) {
  return (lightValue * lightBrigtness) / 255;
}

//our callback functions
void workingLightChanged(EspalexaDevice* d) {
  if (d == nullptr) return;

  if (d->getValue() == 0) {
    ledcWrite(redChannel3, 0);
    ledcWrite(greenChannel3, 0);
    ledcWrite(blueChannel3, 0);
  } else {
    ledcWrite(redChannel3, lightDimming(d->getR(), d->getValue()));
    ledcWrite(greenChannel3, lightDimming(d->getG(), d->getValue()));
    ledcWrite(blueChannel3, lightDimming(d->getB(), d->getValue()));
  }
}

void monitorLightChanged(EspalexaDevice* d) {
  if (d == nullptr) return;

  if (d->getValue() == 0) {
    ledcWrite(redChannel2, 0);
    ledcWrite(greenChannel2, 0);
    ledcWrite(blueChannel2, 0);
  } else {
    ledcWrite(redChannel2, lightDimming(d->getR(), d->getValue()));
    ledcWrite(greenChannel2, lightDimming(d->getG(), d->getValue()));
    ledcWrite(blueChannel2, lightDimming(d->getB(), d->getValue()));
  }
}

void cabinetLightChanged(EspalexaDevice* d) {
  if (d == nullptr) return;

  if (d->getValue() == 0) {
    ledcWrite(redChannel1, 0);
    ledcWrite(greenChannel1, 0);
    ledcWrite(blueChannel1, 0);
  } else {
    ledcWrite(redChannel1, lightDimming(d->getR(), d->getValue()));
    ledcWrite(greenChannel1, lightDimming(d->getG(), d->getValue()));
    ledcWrite(blueChannel1, lightDimming(d->getB(), d->getValue()));
  }
}

void floorLightChanged(EspalexaDevice* d) {
  if (d == nullptr) return;

  if (d->getValue() == 0) {
    ledcWrite(redChannel4, 0);
    ledcWrite(greenChannel4, 0);
    ledcWrite(blueChannel4, 0);
  } else {
    ledcWrite(redChannel4, lightDimming(d->getR(), d->getValue()));
    ledcWrite(greenChannel4, lightDimming(d->getG(), d->getValue()));
    ledcWrite(blueChannel4, lightDimming(d->getB(), d->getValue()));
  }
}

void ledStripsSetup() {
  // setup channels
  ledcSetup(redChannel1, freq, resolution);
  ledcSetup(greenChannel1, freq, resolution);
  ledcSetup(blueChannel1, freq, resolution); 

  ledcSetup(redChannel2, freq, resolution);
  ledcSetup(greenChannel2, freq, resolution);
  ledcSetup(blueChannel2, freq, resolution); 

  ledcSetup(redChannel3, freq, resolution);
  ledcSetup(greenChannel3, freq, resolution);
  ledcSetup(blueChannel3, freq, resolution); 

  ledcSetup(redChannel4, freq, resolution);
  ledcSetup(greenChannel4, freq, resolution);
  ledcSetup(blueChannel4, freq, resolution); 
  
  // attach pins
  ledcAttachPin(redPin1, redChannel1);
  ledcAttachPin(greenPin1, greenChannel1);
  ledcAttachPin(bluePin1, blueChannel1);

  ledcAttachPin(redPin2, redChannel2);
  ledcAttachPin(greenPin2, greenChannel2);
  ledcAttachPin(bluePin2, blueChannel2);

  ledcAttachPin(redPin3, redChannel3);
  ledcAttachPin(greenPin3, greenChannel3);
  ledcAttachPin(bluePin3, blueChannel3);

  ledcAttachPin(redPin4, redChannel4);
  ledcAttachPin(greenPin4, greenChannel4);
  ledcAttachPin(bluePin4, blueChannel4);
}

void setup() {
  Serial.begin(115200);

  ledStripsSetup();

  wifiConnected = connectWifi();

  if (wifiConnected) {
    espalexa.addDevice("arbeitslicht", workingLightChanged, EspalexaDeviceType::color);
    espalexa.addDevice("monitorlicht", monitorLightChanged, EspalexaDeviceType::color);
    espalexa.addDevice("schranklicht", cabinetLightChanged, EspalexaDeviceType::color);
    espalexa.addDevice("bodenbeleuchtung", floorLightChanged, EspalexaDeviceType::color);

    espalexa.begin();
  } else {
    while (1) {
      Serial.println("Cannot connect to WiFi. Please check data and reset the ESP.");
      delay(2500);
    }
  }
  
  // auf dem schrank - cabinet light
/*
  ledcWrite(redChannel1, 255);
  ledcWrite(greenChannel1, 0);
  ledcWrite(blueChannel1, 255);
*/
  // hinter monitoren - monitor light

  /*ledcWrite(redChannel2, 0);
  ledcWrite(greenChannel2, 150);
  ledcWrite(blueChannel2, 0);
  */
  // unterm schrank - working light
/*
  ledcWrite(redChannel3, 0);
  ledcWrite(greenChannel3, 150);
  ledcWrite(blueChannel3, 0); */
}

void loop() {
  espalexa.loop();
  delay(1);
}