#define BLYNK_TEMPLATE_ID "TMPL2TbG1EPUc"
#define BLYNK_TEMPLATE_NAME "Feedback Machine"
#define BLYNK_AUTH_TOKEN "X0ZcPLZjfDvRN1SsEFzvfGG91iKy4mlQ"

#include <BlynkSimpleEsp32.h>
#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold24pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>

#include <Preferences.h>
#include  "Wire.h"

#include <wordwrap.h>

#define GOOD 13
#define OK 12
#define BAD 14

GxEPD2_BW<GxEPD2_750_T7, GxEPD2_750_T7::HEIGHT> display(GxEPD2_750_T7(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));

#define SSID "IHDSB.CA"
#define PASSWORD "HDSBsecure"

String question = "Generic Question";

bool blynkConnected = false;
bool disabled = false;

Preferences preferences;


void setup() {

  pinMode(BAD, INPUT_PULLUP);
  pinMode(OK, INPUT_PULLUP);
  pinMode(GOOD, INPUT_PULLUP);

  preferences.begin("feedback", false); 

  wordwrap.crlf = false;

  display.init(115200, true, 2, false); // USE THIS for Waveshare boards with "clever" reset circuit, 2ms reset pulse

  updateMessage("Connecting to WiFi...");

  Blynk.begin(BLYNK_AUTH_TOKEN, SSID, PASSWORD);


  int retries = 0;

  while (!Blynk.connected()) {
    delay(100);
    retries++;

    if (retries == 600) {
      updateSubtitle("Error 23");
    }
  }

  if (retries >= 600) {
    clearSubtitle();
  }

  // preferences.putInt("bad", 0);
  // preferences.putInt("ok", 0);
  // preferences.putInt("good", 0);

  delay(2000);
}

void loop() {
  //wait  for a second
  while (true) {
    delay(10);

    if (disabled) {
      continue;
    }

    if (digitalRead(GOOD) == LOW) {
      preferences.putInt("good", preferences.getInt("good") + 1);
      Blynk.virtualWrite(V0, preferences.getInt("good"));
      break;
    } else if (digitalRead(OK) == LOW) {
      preferences.putInt("ok", preferences.getInt("ok") + 1);
      Blynk.virtualWrite(V1, preferences.getInt("ok"));
      break;
    } else if (digitalRead(BAD) == LOW) {
      preferences.putInt("bad", preferences.getInt("bad") + 1);
      Blynk.virtualWrite(V2, preferences.getInt("bad"));  //! fix this duplication later
      break;
    }
    Blynk.run();
  }

  updateSubtitle("Thank you for your feedback!");
  delay(1000);
  clearSubtitle();

}

void updateSubtitle(const char message[]) {
  display.setPartialWindow(0, 440, display.width(), 40);
  display.firstPage();

  int16_t tbx, tby; 
  uint16_t tbw, tbh;
  display.getTextBounds(message, 0, 0, &tbx, &tby, &tbw, &tbh);



  do
  {
      display.fillScreen(GxEPD_WHITE);
      display.setCursor(((display.width() - tbw) / 2) - tbx, 460);
      display.setFont(&FreeMonoBold12pt7b);
      display.print(message);

  } while (display.nextPage());
  
}

void clearSubtitle()
{
  display.firstPage();
  do
  {
    display.fillScreen(GxEPD_WHITE);
  } while (display.nextPage());
}

void updateMessage(const char text[])
{
  // Define the maximum number of characters per line
  const int maxLineLength = 25;
  char wrappedText[128]; // Adjust size as needed
  
  wordwrap.wrap(text, maxLineLength).toCharArray(wrappedText, 128);

  display.setRotation(0);
  display.setFont(&FreeMonoBold24pt7b);
  display.setTextColor(GxEPD_BLACK);

  // Calculate the bounding box for the entire wrapped text
  int16_t tbx, tby; 
  uint16_t tbw, tbh;
  display.getTextBounds(wrappedText, 0, 0, &tbx, &tby, &tbw, &tbh);

  // Calculate the x-coordinate to center the text
  uint16_t x = ((display.width() - tbw) / 2) - tbx;

  // Calculate the y-coordinate for the first line
  uint16_t y = ((display.height() - tbh) / 2) - tby;

  display.setFullWindow();
  display.firstPage();
  do
  {
    display.fillScreen(GxEPD_WHITE);

    // Print each line separately
    char *line = strtok(wrappedText, "\n");
    uint16_t lineHeight = 40; // Adjust this value based on your font size

    while (line != NULL)
    {
      display.setCursor(x, y);
      display.print(line);
      y += lineHeight; // Move y-coordinate down for the next line
      line = strtok(NULL, "\n");
    }
  }
  while (display.nextPage());
}

BLYNK_CONNECTED()
{
    Blynk.syncVirtual(V10);
}

BLYNK_WRITE(V10) {

  if (strlen(param.asStr()) > 100) {
    updateSubtitle("Error 31");
    return;
  }

  updateMessage(param.asStr());

  preferences.putInt("bad", 0);
  preferences.putInt("ok", 0);
  preferences.putInt("good", 0);
  Blynk.virtualWrite(V0, 0);
  Blynk.virtualWrite(V1, 0);
  Blynk.virtualWrite(V2, 0);
}

BLYNK_WRITE(V9) {

  if (param.asInt() == 0) {
    disabled = false;
    clearSubtitle();
  }

  if (param.asInt() == 1) {
    disabled = true;
    updateMessage("Out of Order");
    updateSubtitle("Error 42");
  }

}