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

// Διαστάσεις OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Λωρίδα NeoPixel (5 LED στο pin 25)
#define LED_PIN 25
#define NUM_LEDS 5
Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

// Buzzer στο pin 5
#define BUZZER_PIN 5

// Touch buttons (μόνο οι αριθμοί των pins)
#define TOUCH_1 12
#define TOUCH_2 13
#define TOUCH_3 14
#define TOUCH_4 15

const int touchPins[] = {TOUCH_1, TOUCH_2, TOUCH_3, TOUCH_4};
const int ledIndex[] = {4, 3, 2, 1}; // Αντιστοίχηση touch pin → LED

uint32_t ledColor[] = {
  strip.Color(100, 0, 0),   // Κόκκινο
  strip.Color(0, 100, 0),   // Πράσινο
  strip.Color(0, 0, 100),   // Μπλε
  strip.Color(100, 100, 0)  // Κίτρινο
};

// Νότες (συχνότητες)
#define NOTE_G3  196
#define NOTE_A3  220
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_E4  330
#define NOTE_G4  392
#define NOTE_A4  440
#define NOTE_C2  65
#define NOTE_G2  98

// Μεταβλητές παιχνιδιού
int turn = 0;
int randomArray[50];
int inputArray[50];
int highscore = 0;
int myScore = 0;

// Μελωδίες
int startTune[] = {NOTE_E4, NOTE_E4, NOTE_C4, NOTE_E4, NOTE_G4, NOTE_G4};
int startDurations[] = {100, 200, 100, 200, 100, 400};
int failTune[] = {NOTE_G2, NOTE_C2};
int failDurations[] = {300, 300};

void playTone(int frequency, int duration) {
  if (frequency > 0) {
    tone(BUZZER_PIN, frequency, duration);
  }
  delay(duration);
}

// ------------------------------------------------------------
// Έλεγχος LED
// ------------------------------------------------------------
void setLED(int idx, uint32_t color) {
  if (idx >= 0 && idx < NUM_LEDS) {
    strip.setPixelColor(idx, color);
    strip.show();
  }
}

void allLEDs(uint32_t color) {
  for (int i = 0; i < NUM_LEDS; i++) strip.setPixelColor(i, color);
  strip.show();
}

void ledsOff() {
  allLEDs(strip.Color(0, 0, 0));
}

#define TOUCH_THRESHOLD 500   // Κατώφλι πατήματος

bool isTouchPressed(int pin) {
  return touchRead(pin) < TOUCH_THRESHOLD;
}


void fail() {
  noTone(BUZZER_PIN);
 
  // Αναβόσβημα και ήχος λάθους
  for (int i = 0; i < 2; i++) {
    allLEDs(strip.Color(50, 50, 50));
    playTone(failTune[0], failDurations[0]);
    ledsOff();
    playTone(failTune[1], failDurations[1]);
  }
 
  // Εμφάνιση αποτελεσμάτων στην OLED
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print("High: ");
  display.println(highscore);
  display.setCursor(0, 16);
  display.print("You: ");
  display.println(myScore);
  display.display();
  delay(2000);
 
  // Αναμονή για πάτημα οποιουδήποτε κουμπιού (touch)
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Press any");
  display.setCursor(0, 16);
  display.println("to restart");
  display.display();
 
  bool anyPressed = false;
  while (!anyPressed) {
    for (int i = 0; i < 4; i++) {
      if (isTouchPressed(touchPins[i])) {
        anyPressed = true;
        break;
      }
    }
    // Αναβόσβημα LED εν αναμονή
    allLEDs(strip.Color(20, 20, 20));
    delay(100);
    ledsOff();
    delay(100);
  }
  delay(500); // Debounce μετά το πάτημα
 
  turn = 0;
  myScore = 0;
  display.clearDisplay();
}

void input() {
  static unsigned long lastPressTime = 0;
  static int lastButton = -1;
 
  for (int i = 0; i <= turn; ) {
    for (int b = 0; b < 4; b++) {
      if (isTouchPressed(touchPins[b])) {
        if (millis() - lastPressTime < 300 && lastButton == b) {
          continue;
        }
        lastPressTime = millis();
        lastButton = b;
       
        // Άναμμα LED και ήχος
        setLED(ledIndex[b], ledColor[b]);
        playTone( (b == 0) ? NOTE_G3 :
                  (b == 1) ? NOTE_A3 :
                  (b == 2) ? NOTE_B3 : NOTE_C4, 100);
        delay(200); // Χρόνος που μένει το LED αναμμένο
        setLED(ledIndex[b], strip.Color(0, 0, 0));
        delay(250); // Μικρή παύση μετά
       
        inputArray[i] = b + 1; // 1..4
        if (inputArray[i] != randomArray[i]) {
          fail();
          return;
        }
        i++;
        if (i > turn) break;
      }
    }
  }
  turn++;
  myScore = turn;
  if (myScore > highscore) highscore = myScore;
}

void setup() {
  Serial.begin(115200);
 
  // Οθόνη OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println("OLED not found");
    while (1);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(" 1o EPAL SYKEON");
  display.setCursor(0, 16);
  display.println("4LED MEMORY GAME");
  display.display();
   
  // NeoPixel
  strip.begin();
  ledsOff();
 
  randomSeed(analogRead(0));
 
  // Μελωδία έναρξης
  for (int i = 0; i < 6; i++) {
    playTone(startTune[i], startDurations[i]);
    if (i == 0 || i == 2) setLED(ledIndex[0], ledColor[0]);
    if (i == 1 || i == 3) setLED(ledIndex[1], ledColor[1]);
    if (i == 4 || i == 5) setLED(ledIndex[2], ledColor[2]);
    delay(25);
    ledsOff();
  }
  delay(1000);
  display.clearDisplay();
}

void loop() {
  // Εισαγωγή νέου γύρου (προαιρετικά αναβοσβήνουν όλα)
  for (int i = 0; i < 3; i++) {
    allLEDs(strip.Color(50, 50, 50));
    playTone(NOTE_A4, 100);
    ledsOff();
    delay(200);
  }
  delay(500);
 
  // Εμφάνιση σκορ
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("You: ");
  display.println(myScore);
  display.setCursor(0, 16);
  display.print("High: ");
  display.println(highscore);
  display.display();
  delay(1000);
 
  // Δημιουργία νέας τυχαίας τιμής
  randomArray[turn] = random(1, 5);
 
  // Παρουσίαση της ακολουθίας
  for (int i = 0; i <= turn; i++) {
    int val = randomArray[i];
    setLED(ledIndex[val-1], ledColor[val-1]);
    playTone( (val==1)?NOTE_G3 : (val==2)?NOTE_A3 : (val==3)?NOTE_B3 : NOTE_C4, 100);
    delay(400);
    ledsOff();
    delay(100);
  }
 
  // Λήψη εισόδου
  input();
 
  delay(500);
}