#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH        128 // OLED display width, in pixels
#define SCREEN_HEIGHT        64 // OLED display height, in pixels
#define OLED_RESET            -1 // Reset pin # (or -1 if sharing Arduino reset pin)

#define SNAKE_PIECE_SIZE     3
#define MAX_SANKE_LENGTH   165
#define MAP_SIZE_X          20
#define MAP_SIZE_Y          20
#define STARTING_SNAKE_SIZE  5
#define SNAKE_MOVE_DELAY    30

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const byte buttonPins[] = {4, 2, 5, 3}; // LEFT, UP, RIGHT, DOWN

typedef enum {
  START,
  RUNNING,
  GAMEOVER
} State;

typedef enum {
    LEFT,
    UP,
    RIGHT,
    DOWN
} Direction;

State gameState;
int8_t snake[MAX_SANKE_LENGTH][2];
uint8_t snake_length;
Direction dir;
Direction newDir;

int8_t fruit[2];

void setupGame() {
  gameState = START;
  dir = RIGHT;
  newDir = RIGHT;
  resetSnake();
  generateFruit();
  display.clearDisplay();
  drawMap();
  drawScore();
  drawPressToStart();
  display.display();
}

void setup() {
  Serial.begin(9600);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
		Serial.println(F("SSD1306 allocation failed"));
		for (;;)
			;
	}
  for (byte i = 0; i < 4; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  randomSeed(analogRead(A0));
  setupGame();
}

int moveTime = 0;
void loop() {
  switch(gameState) {
    case START:
      if(buttonPress()) gameState = RUNNING;
      break;
    

    case RUNNING:
      moveTime++;
      readDirection();
      if(moveTime >= SNAKE_MOVE_DELAY) {
        dir = newDir;
        display.clearDisplay();
        if(moveSnake()) {
          gameState = GAMEOVER;
          drawGameover();
          delay(1000);
        }
        drawMap();
        drawScore();
        display.display();
        checkFruit();
        moveTime = 0;
      }
      break;
    
    case GAMEOVER:
      if(buttonPress()) {
        delay(500);
        setupGame();
        gameState = START;
      }
      break;
  }
  
  delay(10);
  display.display();
}

void displayTime() {
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.print("TIME:");
  display.setCursor(15, 20);
  display.print(currentTime.hours < 10 ? "0" : "");
  display.print(currentTime.hours);
  display.print(":");
  display.print(currentTime.minutes < 10 ? "0" : "");
  display.print(currentTime.minutes);
  display.print(":");
  display.print(currentTime.seconds < 10 ? "0" : "");
  display.print(currentTime.seconds);
}

void checkButtons() {
  // Implement button logic for setting time and alarm
  if (btnB.wasPressed() || btnG.wasPressed())
  {
    setTime();
  }
}

void setTime()
{
  // Handle Hours
  currentTime.seconds=0;
  if(btnG.isPressed())
  {
    currentTime.hours++;
  }
  if (btnG.wasLongPressed() ) {
    static unsigned long pm=cm;
    if((cm-pm)>=200)
    {
      currentTime.hours++;
      pm=cm;
    }
  }
  if(currentTime.hours>23)   currentTime.hours=0;

  // Handle minutes
  if(btnB.isPressed())
  {
    currentTime.minutes++;
  }
  if (btnB.wasLongPressed() ) {
    static unsigned long pm=cm;
    if((cm-pm)>=200)
    {
      currentTime.minutes++;
      pm=cm;
    }
  }
  if(currentTime.minutes>59)   currentTime.minutes=0;
}


//ISR: Interrupt Service Routine:
void updateTime() {
  if(!btnB.wasPressed()) currentTime.incrementSeconds();
}