#include <EEPROM.h>

//RFID
#include <SPI.h>
#include <MFRC522.h>

constexpr uint8_t RST_PIN = D0;  // Configurable
constexpr uint8_t SS_PIN = D8;   // Configurable

MFRC522 rfid(SS_PIN, RST_PIN);  // Instance of the class
MFRC522::MIFARE_Key key;

//WIFI
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

char ssid[] = "NetName";               // your network SSID (name)
char password[] = "NetPassword";  // your network key

bool connected;

WiFiClient client;
#define HOST "api.wesleydegraaf.com"

//Time
unsigned long oldTime;
unsigned long deltaTime;

bool disableLightsAfterTimer;
float lightsTimer;

float buttonTimer;
bool settingMode;
bool buttonTriggerd;
bool settingButton;
int currentIndex;

void WriteIntIntoEEPROM(int address, int number) {
  EEPROM.write(address, number >> 8);
  EEPROM.write(address + 1, number & 0xFF);
  EEPROM.commit();
}

int ReadIntFromEEPROM(int address) {
  return (EEPROM.read(address) << 8) + EEPROM.read(address + 1);
}

void setup() {
  EEPROM.begin(512);

  pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);
  pinMode(D3, OUTPUT);
  pinMode(D4, OUTPUT);

  //Enables the startup light.
  ShowLeds(false, false, true);
  tone(D2, 350, 700);

  currentIndex = ReadIntFromEEPROM(42);

  // Connect to the WiFI
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  WiFi.begin(ssid, password);

  int connectTryCount = 0;
  while (WiFi.status() != WL_CONNECTED) {
    ShowLeds(true, true, true);
    delay(1000);

    connectTryCount++;
    if (connectTryCount >= 20) {
      ShowLeds(true, false, false);
      return;
    }
  }

  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);

  ShowLeds(false, true, false);
  delay(500);

  IPAddress ip = WiFi.localIP();

  //START RFID
  SPI.begin();      // Init SPI bus
  rfid.PCD_Init();  // Init MFRC522

  ShowLeds(false, false, false);
}

void loop() {
  //DeltaTime
  unsigned long currentTime = millis();
  deltaTime = currentTime - oldTime;
  oldTime = currentTime;

  if (disableLightsAfterTimer) {
    lightsTimer -= deltaTime;
    if (lightsTimer <= 0) {
      disableLightsAfterTimer = false;
      ShowLeds(false, false, false);
    }
  }

  if (analogRead(A0) >= 1000) {
    buttonTimer += deltaTime;

    if (buttonTimer >= 4 * 1000 && !settingButton) {
      settingMode = !settingMode;
      if (settingMode) {
        tone(D2, 800, 750);
        BinaryLed();
      } else {
        tone(D2, 300, 750);
        ShowLeds(false, false, false);
        WriteIntIntoEEPROM(currentIndex, 2);
      }
      settingButton = true;
    } else if (buttonTimer < 4 * 1000 && settingMode && !buttonTriggerd) {
      buttonTriggerd = true;
    }
  } else {
    if (!settingButton && settingMode && buttonTriggerd) {
      buttonTriggerd = true;
      currentIndex++;

      if (currentIndex >= 8) currentIndex = 0;
      BinaryLed();
    }

    buttonTriggerd = false;
    settingButton = false;
    buttonTimer = 0;
  }

  if (settingMode) return;

  String result = GetID();

  if (WiFi.status() != WL_CONNECTED && connected) {
    connected = false;
    ShowLeds(true, false, true);
  } else if (WiFi.status() == WL_CONNECTED && !connected) {
    connected = true;
    ShowLeds(false, false, false);
  }

  if (result != "") {
    MakeRequest(result);
  }
}

void BinaryLed() {
  String binary_string = String(currentIndex, BIN);

  while (binary_string.length() < 3) {
    binary_string = "0" + binary_string;
  }

  bool led1 = binary_string.charAt(0) == '1';
  bool led2 = binary_string.charAt(1) == '1';
  bool led3 = binary_string.charAt(2) == '1';

  ShowLeds(led1, led2, led3);
}

String GetID() {
  if (!rfid.PICC_IsNewCardPresent()) {
    return "";
  }

  if (!rfid.PICC_ReadCardSerial()) return "";

  String NFCID = "";

  byte nuidPICC[4];

  for (byte i = 0; i < 4; i++) {
    // Adds the 4 bytes in a single String variable
    NFCID.concat(String(rfid.uid.uidByte[i], HEX));
  }

  NFCID.toUpperCase();
  rfid.PICC_HaltA();  // Stop reading
  return NFCID;
}

void ShowLeds(bool red, bool green, bool blue) {
  digitalWrite(D1, red ? HIGH : LOW);
  digitalWrite(D3, green ? HIGH : LOW);
  digitalWrite(D4, blue ? HIGH : LOW);
}

void ConfirmSound() {
  tone(D2, 1000, 200);  // Eerste toon (1 kHz) voor 200 milliseconden
  delay(250);           // Wacht 250 milliseconden voordat de volgende toon wordt afgespeeld
  tone(D2, 1500, 200);  // Tweede toon (1.5 kHz) voor 200 milliseconden
  delay(250);           // Wacht 250 milliseconden voordat de volgende toon wordt afgespeeld
  noTone(D2);           // Stop met het afspelen van de toon
}

void PlayRejectSound() {
  tone(D2, 500, 1000);
}

void MakeRequest(String uid) {
  HTTPClient http;

  if (http.begin(client, "http://YourSite/LapUpdate.php?NFCUID=" + uid + "&DeviceID=" + currentIndex)) {  // HTTP
    // start connection and send HTTP header
    int httpCode = http.GET();

    // httpCode will be negative on error
    if (httpCode > 0) {
      // HTTP header has been send and Server response header has been handled

      // file found at server
      if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
        String payload = http.getString();
        if (payload == "OK") {
          ShowLeds(false, true, false);
          ConfirmSound();
        } else {
          ShowLeds(true, false, false);
          PlayRejectSound();
        }

        lightsTimer = 2 * 1000;
        disableLightsAfterTimer = true;
      }
    }

    http.end();
  }
}