// Core Libs
#include <WiFi.h>
#include <WiFiUdp.h>
#include <Ticker.h>

// Downloaded Libs
#include <NTPClient.h>
#include <ThingSpeak.h>
#include <OneButton.h>
#include <RotaryEncoder.h>

// Projet Libs
#include "SystemDisplay.h"

// Wifi credentials
#define SECRET_SSID "MySSID"		// replace MySSID with your WiFi network name
#define SECRET_PASS "MyPassword"	// replace MyPassword with your WiFi password

// ThingSpeak credentials
#define SECRET_CH_ID 0000000			// replace 0000000 with your channel number
#define SECRET_WRITE_APIKEY "XYZ"   // replace XYZ with your channel write API Key
#define SECRET_READ_APIKEY "XYZ"   // replace XYZ with your channel write API Key

// Program Behavior
#define DISPLAY_REFRESH_RATE 5.0 // In s. Refresh rate of the screen
#define FEED_INTERVAL 8*3600  // In s. Minimum time between feed
#define HAPPY_DURATION 5 // In s. Duration of the happy face
#define SLEEP_HOUR_START 22  // Cat's bedtime hour
#define SLEEP_HOUR_STOP 6  // Cat wake-up hour

// Used PINS
#define SDA_PIN 8
#define SCL_PIN 9
#define BUTTON_SELECT_PIN 10
#define ENCODER_A_PIN 20
#define ENCODER_B_PIN 21

// Wifi
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;
WiFiClient client;

// ThingSpeak
int statusCode = 0;

// NTP
WiFiUDP ntpUDP;
NTPClient NTP(ntpUDP, "pool.ntp.org", 0 * 3600, 2 * 3600000); // Update every 2 hours

// OLED
SystemDisplay oled;
Ticker tickerDisplaySwitch;

// Bouton
OneButton btnSelect(BUTTON_SELECT_PIN);
RotaryEncoder encoder(ENCODER_B_PIN, ENCODER_A_PIN, RotaryEncoder::LatchMode::TWO03);

// System
uint32_t lastFeed = 0;

void toggleDisplay()
{
  uint32_t enlapsedTime = NTP.getEpochTime() - lastFeed;
  bool recentFeed = enlapsedTime < HAPPY_DURATION;
  bool feed = enlapsedTime > FEED_INTERVAL;
  bool sleep = (NTP.getHours()>=SLEEP_HOUR_START) || (NTP.getHours()<SLEEP_HOUR_STOP);
  if (recentFeed)
    oled.love();
  else if (sleep)
    oled.sleep();
  else if (feed)
    oled.angry();
  else
    oled.normal();
}

void clickFunction ()
{
  lastFeed = NTP.getEpochTime() - 1;
  toggleDisplay();
  ThingSpeak.writeField(SECRET_CH_ID, 1, String(lastFeed), SECRET_WRITE_APIKEY);
}

void setup()
{
  // Setup serial
  Serial.begin(115200);
  Serial.println("\nStarted");

  // Setup the button
  btnSelect.setDebounceMs(50);
  btnSelect.attachClick(clickFunction);

  // Setup OLED
  oled.begin();
  oled.close(); // Close eyes, not close class !

  // Setup Wifi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  if (WiFi.waitForConnectResult() != WL_CONNECTED)
  {
    Serial.printf("Failed!\n");
    return;
  }
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Setup NTP
  NTP.begin();
  NTP.forceUpdate();

  // Setup ThingSpeak
  ThingSpeak.begin(client);
  lastFeed = strtoul(ThingSpeak.readStringField(SECRET_CH_ID, 1, SECRET_READ_APIKEY).c_str(), NULL, 10);
  statusCode = ThingSpeak.getLastReadStatus();
  if (statusCode != 200)
  {
    lastFeed = NTP.getEpochTime() - HAPPY_DURATION;
  }

  tickerDisplaySwitch.attach(DISPLAY_REFRESH_RATE, toggleDisplay);

  oled.normal();

  Serial.printf("Setup End\n");
}

void loop()
{
  NTP.update();
  btnSelect.tick();
  encoder.tick();

  // encoder
  static uint32_t pos = 0;
  uint32_t newPos = encoder.getPosition();
  if (pos != newPos) {
    oled.happy();
    // RAZ timer
    tickerDisplaySwitch.detach();
    tickerDisplaySwitch.attach(DISPLAY_REFRESH_RATE, toggleDisplay);
    pos = newPos;
  }
}