#include "pomodoEnum.hpp"
#include "LedControl.h"
#include "binary.h"
#include "ReadEncoderUtils.cpp"
#include "DisplayManager.hpp"
#include "PomodoCompanion.cpp"

#define ENCODER_CLK 21
#define ENCODER_DT  20
#define ENCODER_SW  19

#define BUTTON_PIN 5

const int SPEAKER_PIN = 21;

DisplayManager dm(12, 11, 10, 9, 8, 7);
PomodoCompanion pc(25, 5, 4, 0);
ReadEncoderUtils re(ENCODER_CLK, ENCODER_DT, ENCODER_SW);

int counter = 0;

int lastClk = HIGH;


volatile int encoderState;
volatile int previousEncoderState;
volatile boolean displayRefreshNeeded = true;

void encoderISR() {
  if (digitalRead(ENCODER_CLK) == LOW) {
    encoderState = digitalRead(ENCODER_DT);
    
    // if (encoderState != previousEncoderState) {
      pc.updateValue(re.readEncoder());
      displayRefreshNeeded = true;
    // }
    
    previousEncoderState = encoderState;
  }
}

long int modeLastChanged = 0;
long int lastRotaryChanged = 0;

void handlePushButton() {
  if (re.readPushButton() && millis() - modeLastChanged > 300) {
    modeLastChanged = millis();
    Pomodo state = pc.setNextState();
    if (state != FOCUS_TIME || state != BREAK_TIME)
      displayRefreshNeeded = true;
  }
}
void setup() {
  Serial.begin(115200);
  pinMode(ENCODER_CLK, INPUT);
  pinMode(ENCODER_DT, INPUT);
  pinMode(ENCODER_SW, INPUT_PULLUP);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), encoderISR, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENCODER_SW), [] () {handlePushButton();}, FALLING);
  dm.DisplayText("Hi! Let's start a new session \x03");
  delay(1500);
  dm.clear();
  // workTime = GetFocusTime();
}

// [X] - Create function getting/setting FocusTime/BreakTime/NbRounds
// [X] - Start Timer
// [ ] - Buzz sound
// [X] - Button to go next
// [ ] - Button to restart

LiquidCrystal* lc = dm.getLiquidCrystal();

const unsigned long interval = 1000;
unsigned long previousMillis = 0;
int remainingMinutes;
int remainingSeconds;
unsigned long currentMillis;

bool isFirstPart = true;

void sessionRecapDisplay() {
  lc->clear();
  if (isFirstPart) {
    lc->print("Focus ");
    lc->print(pc.getFocusTime());
    lc->print(" min");
    lc->setCursor(0, 2);
    lc->print("Break ");
    lc->print(pc.getBreakTime());
    lc->print(" min");
    isFirstPart = !isFirstPart;
    delay(1000);
  } else {
    lc->print("Rounds ");
    lc->print(pc.getNbRounds());
    lc->print("x");
    lc->setCursor(0, 2);
    lc->print("Total ");
    lc->print((pc.getFocusTime() + pc.getBreakTime()) * pc.getNbRounds());
    lc->print(" min");
    isFirstPart = !isFirstPart;
    delay(1000);
  }
}

void StateDisplayManager() {
  Pomodo state = pc.getPomodoState();
  switch(state) {
    case SET_FOCUS_TIME: 
      lc->clear();
      lc->print("Let's setup ^.^");
      lc->setCursor(0,2);
      lc->print("Focus Time: ");
      lc->print(pc.getFocusTime());
      displayRefreshNeeded = false;
      break;
    case SET_BREAK_TIME:
      lc->clear();
      lc->print("Time to drink !");
      lc->setCursor(0,2);
      lc->print("BreakTime: ");
      lc->print(pc.getBreakTime());
      displayRefreshNeeded = false;
      break;
    case NB_POMODO_ROUND:
      lc->clear();
      lc->print("Nearly there D:");
      lc->setCursor(0,2);
      lc->print("Nb Rounds: ");
      lc->print(pc.getNbRounds());
      displayRefreshNeeded = false;
      break;
    case SESSION_RECAP: 
      sessionRecapDisplay();
      break;
    case SUMMARY:
      lc->clear();
      lc->print("FINISHED OMG GG");
      displayRefreshNeeded = false;
      break;
  }
}
bool nextTimer = true;
bool needUpdateRound = false;

int lastState = HIGH;
void handleNextBtn() {
  int value = digitalRead(BUTTON_PIN);
  if (lastState != value) {
    if (value == LOW) {
      Pomodo state = pc.setNextState();
      if (state == FOCUS_TIME || state == BREAK_TIME) {
        nextTimer = true;
      } else {
        displayRefreshNeeded = true;
      }
    }
  }
}

void TimeHelper(
    int baseMinutes, 
    int baseSeconds, 
    char* label, 
    bool countAsRound = false
) {
  if (nextTimer) {
    tone(6, 262, 250);
    previousMillis = millis();
    remainingMinutes = baseMinutes;
    remainingSeconds = baseSeconds;

    lc->clear();
    lc->print("   ");
		lc->print(label);
		lc->print(" Time  ");

    nextTimer = false;
    needUpdateRound = true;
	} else if (!nextTimer && (currentMillis - previousMillis >= interval)) {
		previousMillis = currentMillis;

    if (remainingMinutes > 0 || remainingSeconds > 0) {
      if (remainingSeconds == 0) {
        remainingMinutes--;
        remainingSeconds = 59;
      } else {
        remainingSeconds--;
      }

			lc->setCursor(0,2);
			lc->print("                ");
      lc->setCursor(5, 2);
      lc->print(remainingMinutes);
      lc->print(" : ");
      lc->print(remainingSeconds);
    } else {
      if (countAsRound && needUpdateRound ) {
        pc.setCurrentRound(pc.getCurrentRound() + 1);
        
        needUpdateRound = false;
      }

        lc->clear();
        lc->print("End ");
				lc->print(label);
				lc->print(" ");
        lc->print(pc.getCurrentRound());
        lc->print("! :D");
        lc->setCursor(0, 2);

        if (pc.isSessionComplete()) {
          lc->print("Btn to finish!");
          tone(6, 262, 400);
        } else {
          lc->print("Btn for ");
					lc->print(countAsRound ? "Break" : "Focus");
					lc->print("!");
          tone(6, 262, 400);
        }

      handleNextBtn();
		}
	}
}

void timerManagerDisplay() {
  Pomodo state = pc.getPomodoState();
  if (state == FOCUS_TIME) {
    TimeHelper(pc.getFocusTime(), 0, "Focus", true);
  } else if (state == BREAK_TIME) {
    TimeHelper(pc.getBreakTime(), 0, "Break");
  }
}

void loop() {
  currentMillis = millis();

  if (displayRefreshNeeded) {
    StateDisplayManager();
    // delay(300);
  } 

  timerManagerDisplay();
}


/*
// void focusTimer() {
//   if (nextTimer) {
//     // remainingMinutes = pc.getWorkTime();
//     previousMillis = millis();
//     remainingMinutes = 0;
//     remainingSeconds = 3;

//     lc->clear();
//     lc->print("   Focus Time  ");
//     lc->setCursor(5, 2);

//     nextTimer = false;
//     needUpdateRound = true;
//   } else if (!nextTimer && (currentMillis - previousMillis >= interval)) {
//     previousMillis = currentMillis;

//     if (remainingMinutes > 0 || remainingSeconds > 0) {
//       if (remainingSeconds == 0) {
//         remainingMinutes--;
//         remainingSeconds = 59;
//       } else {
//         remainingSeconds--;
//       }
//       lc->setCursor(5, 2);
//       lc->print(remainingMinutes);
//       lc->print(" : ");
//       lc->print(remainingSeconds);
//     } else {
//       if (needUpdateRound) {
//         pc.setCurrentRound(pc.getCurrentRound() + 1);
//         needUpdateRound = false;
//       }

//         lc->clear();
//         lc->print("End focus ");
//         lc->print(pc.getCurrentRound());
//         lc->print("! :D");
//         lc->setCursor(0, 2);

//         if (pc.isSessionComplete()) {
//           lc->print("Btn to finish!");
//         } else {
//           lc->print("Btn for Break!");
//         }

//       handleNextBtn();
//     }
//   }
// }
*/
uno:SCL
uno:SDA
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:14
uno:15
uno:16
uno:17
uno:18
uno:19
uno:20
uno:21
uno:5V.1
uno:5V.2
uno:22
uno:23
uno:24
uno:25
uno:26
uno:27
uno:28
uno:29
uno:30
uno:31
uno:32
uno:33
uno:34
uno:35
uno:36
uno:37
uno:38
uno:39
uno:40
uno:41
uno:42
uno:43
uno:44
uno:45
uno:46
uno:47
uno:48
uno:49
uno:50
uno:51
uno:52
uno:53
uno:GND.4
uno:GND.5
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
uno:A6
uno:A7
uno:A8
uno:A9
uno:A10
uno:A11
uno:A12
uno:A13
uno:A14
uno:A15
$abcdeabcde151015202530354045505560fghijfghij
encoder1:CLK
encoder1:DT
encoder1:SW
encoder1:VCC
encoder1:GND
lcd1:VSS
lcd1:VDD
lcd1:V0
lcd1:RS
lcd1:RW
lcd1:E
lcd1:D0
lcd1:D1
lcd1:D2
lcd1:D3
lcd1:D4
lcd1:D5
lcd1:D6
lcd1:D7
lcd1:A
lcd1:K
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r
bz1:1
bz1:2
r1:1
r1:2