#define ENABLE_GxEPD2_GFX 0

#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <esp_wifi.h>
#include <esp_bt.h>

#include "credentials.h"
#include "logo.h"


#if defined(ESP32)
GxEPD2_BW<GxEPD2_750, GxEPD2_750::HEIGHT> display(GxEPD2_750(/*CS=*/ 15, /*DC=*/ 27, /*RST=*/ 26, /*BUSY=*/ 25));
#endif

#define uS_TO_S_FACTOR 1000000    // Conversion of seconds (S) to microseconds (uS)
#define SLEEPING_TIME 1800        // Time in Seconds e.g. 1800s = 0.5 hours
RTC_DATA_ATTR int bootCount = 0;  // Boot counter after deep sleep

// Creating instances
WiFiClientSecure client;

void setup() {
  Serial.begin(115200);
  display.init(115200);
  SPI.end();                        // Do not use standard SPI pins
  SPI.begin(13, 12, 14, 15);        // Remap SPI pins for Waveshare ESP32 module
  display.fillScreen(GxEPD_WHITE);
  display.setRotation(3);           // Rotate Dislay orientation 180°
  Serial.println("DEBUG: Setup EPD Display complete");
  delay(2000);
  connectToWifi();
  esp_sleep_enable_timer_wakeup(SLEEPING_TIME * uS_TO_S_FACTOR);
  ++bootCount;
  Serial.println("INFO: Boot number: " + String(bootCount));
}

void loop() {
  DisplayShowerthought();
  Serial.println("INFO: Going to deep sleep");
  esp_wifi_stop();
  esp_bt_controller_disable();
  esp_deep_sleep_start();
}


//////////////////////////////////////////////////
/////              WiFi Setup                /////
//////////////////////////////////////////////////

void connectToWifi() {
  WiFi.begin(ssid, password);
  Serial.print("WIFI: Connecting ");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("WIFI: Connected to network");
  Serial.println(WiFi.localIP());
  Serial.println(WiFi.macAddress());
}


const char GreeterText[] = "Reddit | Showerthoughts";

void DisplayShowerthought() {
  Serial.println("DEBUG: Showing greeting screen");
  //display.setRotation(3);
  display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);
  int16_t tbx, tby; uint16_t tbw, tbh;
  display.getTextBounds(GreeterText, 0, 0, &tbx, &tby, &tbw, &tbh);
  uint16_t x = ((display.width() - tbw) / 2) - tbx;
  uint16_t y = ((display.height() - tbh) / 2) - tby;
  display.setFullWindow();
  display.firstPage();  // Full refresh
  String Thought = getShowerthought();
  do {    
    display.fillScreen(GxEPD_WHITE);
    display.drawBitmap(130, 90, logo, 125, 125, GxEPD_BLACK);
    display.setCursor(x, y);
    display.print(GreeterText);
    display.drawRect(x-16, y-20, tbw+32, tbh+18, GxEPD_BLACK);
    display.setCursor(0, 450);
    display.print(Thought);
  }
  while (display.nextPage());
}


//////////////////////////////////////////////////
/////              Reddit utils              /////
//////////////////////////////////////////////////
String getShowerthought() {
  // Connect to reddit.com and fetch the showerthought data using the web client
  Serial.println("Fetching Showerthougt");
  if(!client.connect(host, port)) {
    Serial.println("connection 1 failed!");
    return "Impossible to connect to Reddit";
  }
  String url = "/r/Showerthoughts/random.json?sort=hot&limit=1&t=day";
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: ESP32/0.1\r\n" + 
               "Connection: close\r\n\r\n");
  unsigned long timeout = millis();
  while (client.available() == 0) {
      if (millis() - timeout > 5000) {
          Serial.println(">>> Client Timeout !");
          client.stop();
          return "Reddit did not respond in time";
      }
  }

  // get the random post url (redirection)
  String headerLine = "";
  String locationUrl;
  while(headerLine != "\r") {
    headerLine = client.readStringUntil('\n');
    if(headerLine.indexOf("location: ") ==0) {
      locationUrl = headerLine.substring(10, headerLine.indexOf("?"));
      break;
    }
  }
  client.stop();
  // get the content of the url we just got
  if(!client.connect(host, port)) {
    Serial.println("connection 2 failed!");
    return "Impossible to reconnect to Reddit";
  }
  client.print(String("GET ") + locationUrl + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: ESP32/0.1\r\n" + 
               "Connection: close\r\n\r\n");
  timeout = millis();
  while (client.available() == 0) {
      if (millis() - timeout > 5000) {
          Serial.println(">>> Client Timeout !");
          client.stop();
          return "Shower thought did not arrived in time";
      }
  }
  // get rid of header
  while(client.connected()) {
    String line = client.readStringUntil('\n');
    if (line == "\r") {
      Serial.println("headers received");
      break;
    }
  }
  // Get the response from the reddit.com server
  String quote = client.readStringUntil('\n');
  client.stop();
  // As the JSON-formatted response text can be too long, we'll parse it manually instead of using ArduinoJson
  int quote_start = quote.indexOf("\"title\"");
  // The showerthought quote ends right before a ', "' substring
  int quote_end = quote.indexOf(", \"", quote_start+1); // we start the search from the position where "title" is
  String showerthought = quote.substring(quote_start+9, quote_end);
  // Sanitize the string a bit
  showerthought.replace("\\\"","'"); // get rid of escaped quotes in the text ('\"')
  int junkIndex = showerthought.indexOf("\\u");
  while(junkIndex >= 0) {
    showerthought.remove(junkIndex, 5);
    showerthought.setCharAt(junkIndex, '\'');
    junkIndex = showerthought.indexOf("\\u");
  }
  return showerthought;
  Serial.print(showerthought);
}
