/*
 * Gesture Control with PAJ7620U2 + OLED + Buzzer + Relay + Web Server
 * ARD:icon II IoT - ESP32 Dev Module
 * Λειτουργίες: WiFi Access Point ή Station
 */

#include <Wire.h>
#include <DFRobot_PAJ7620U2.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <WiFi.h>
#include <WebServer.h>

// ========== ΡΥΘΜΙΣΕΙΣ ΛΕΙΤΟΥΡΓΙΑΣ WiFi ==========
#define WIFI_MODE_AP 0     // 0 = Access Point (δημιουργεί δικό του δίκτυο)
#define WIFI_MODE_STA 1    // 1 = Station (συνδέεται σε υπάρχον router)
int wifiMode = WIFI_MODE_AP;   // ΑΛΛΑΞΕ ΕΔΩ για εναλλαγή

// Αν χρησιμοποιείς Station (wifiMode = 1), συμπλήρωσε τα δικά σου:
const char* ssid = "Redmi";       // Όνομα δικτύου
const char* password = "12345678";

// ========== OLED ==========
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// ========== ΑΙΣΘΗΤΗΡΑΣ PAJ7620U2 ==========
DFRobot_PAJ7620U2 paj;

// ========== ΕΞΟΔΟΙ ==========
#define BUZZER_PIN 5
#define RELAY_PIN 16

// ========== ΜΕΤΑΒΛΗΤΕΣ ==========
String lastGesture = "None";
bool relayState = LOW;
unsigned long lastGestureTime = 0;
const unsigned long debounceTime = 300;  // ms μεταξύ χειρονομιών
WebServer server(80);

// Για feedback buzzer
void beep(int duration, int frequency = 2000) {
  tone(BUZZER_PIN, frequency);
  delay(duration);
  noTone(BUZZER_PIN);
}

// ========== ΜΕΤΑΤΡΟΠΗ ΧΕΙΡΟΝΟΜΙΑΣ ΣΕ STRING ==========
String gestureToString(DFRobot_PAJ7620U2::eGesture_t gesture) {
  switch(gesture) {
    case paj.eGestureUp: return "UP";
    case paj.eGestureDown: return "DOWN";
    case paj.eGestureLeft: return "LEFT";
    case paj.eGestureRight: return "RIGHT";
    case paj.eGestureForward: return "FORWARD";
    case paj.eGestureBackward: return "BACKWARD";
    case paj.eGestureClockwise: return "CLOCKWISE";
    case paj.eGestureAntiClockwise: return "COUNTER_CW";
    default: return "None";
  }
}

// ========== ΕΝΕΡΓΕΙΕΣ ΑΝΑ ΧΕΙΡΟΝΟΜΙΑ ==========
void handleGesture(DFRobot_PAJ7620U2::eGesture_t gesture) {
  String gestureName = gestureToString(gesture);
  lastGesture = gestureName;
 
  // Ηχητική επιβεβαίωση (σύντομο μπιπ)
  beep(80, 2500);
 
  // Λογική ελέγχου ρελέ (παράδειγμα)
  if (gesture == paj.eGestureUp) {
    digitalWrite(RELAY_PIN, HIGH);
    relayState = HIGH;
    Serial.println("→ Relay ON (UP)");
    beep(150, 2000);  // μακρύτερο μπιπ για επιβεβαίωση
  }
  else if (gesture == paj.eGestureDown) {
    digitalWrite(RELAY_PIN, LOW);
    relayState = LOW;
    Serial.println("→ Relay OFF (DOWN)");
    beep(150, 2000);
  }
  // Προαιρετικά: άλλες χειρονομίες μπορούν να κάνουν άλλες ενέργειες
  else if (gesture == paj.eGestureLeft) {
    // π.χ. αναβοσβήνει η οθόνη
    Serial.println("← Left gesture - no relay action");
  }
  else if (gesture == paj.eGestureRight) {
    Serial.println("→ Right gesture - no relay action");
  }
 
  // Ενημέρωση οθόνης
  updateDisplay();
}

// ========== ΕΝΗΜΕΡΩΣΗ OLED ==========
void updateDisplay() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("=== GESTURE CTRL ===");
  display.setTextSize(2);
  display.setCursor(0, 18);
  display.print("Last:");
  display.println(lastGesture);
  display.setTextSize(1);
  display.setCursor(0, 42);
  display.print("Relay: ");
  display.println(relayState ? "ON " : "OFF");
  // Εμφάνιση IP ή λειτουργίας
  display.setCursor(0, 52);
  if(wifiMode == WIFI_MODE_AP) {
    display.print("AP: " + WiFi.softAPIP().toString());
  } else {
    display.print(WiFi.localIP());
  }
  display.display();
}

// ========== HTML ΙΣΤΟΣΕΛΙΔΑΣ ==========
String getHTML() {
  String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
  <meta charset='UTF-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
  <title>Gesture Control ARD:icon II</title>
  <style>
    body { font-family: Arial; text-align: center; background: #1a1a2e; color: white; margin: 0; padding: 20px; }
    .container { max-width: 600px; margin: 0 auto; background: #16213e; border-radius: 30px; padding: 20px; box-shadow: 0 0 20px rgba(0,0,0,0.5); }
    h1 { color: #e94560; }
    .gesture-box { background: #0f3460; border-radius: 20px; padding: 20px; margin: 20px 0; }
    .gesture { font-size: 40px; font-weight: bold; color: #e94560; }
    .relay-state { font-size: 24px; margin: 10px; }
    button { background: #e94560; border: none; padding: 12px 25px; font-size: 18px; border-radius: 50px; cursor: pointer; margin: 5px; transition: 0.2s; }
    button:hover { opacity: 0.8; transform: scale(1.02); }
    .on { background: #2ecc71; }
    .off { background: #e74c3c; }
    .footer { margin-top: 20px; font-size: 12px; opacity: 0.7; }
  </style>
  <script>
    function fetchData() {
      fetch('/data')
        .then(response => response.json())
        .then(data => {
          document.getElementById('lastGesture').innerText = data.gesture;
          document.getElementById('relayState').innerText = data.relay ? "ON 🔥" : "OFF ❄️";
          document.getElementById('relayState').style.color = data.relay ? "#2ecc71" : "#e74c3c";
        })
        .catch(err => console.log('Error:', err));
    }
    function setRelay(state) {
      fetch('/relay?state=' + state)
        .then(() => fetchData());
    }
    setInterval(fetchData, 1000);
    window.onload = fetchData;
  </script>
</head>
<body>
<div class='container'>
  <h1>🎮 Gesture Control</h1>
  <div class='gesture-box'>
    <div>Τελευταία χειρονομία:</div>
    <div class='gesture' id='lastGesture'>---</div>
  </div>
  <div class='relay-state'>
    Ρελέ: <span id='relayState'>---</span>
  </div>
  <div>
    <button class='on' onclick='setRelay(1)'>🔛 ON</button>
    <button class='off' onclick='setRelay(0)'>🔴 OFF</button>
  </div>
  <div class='footer'>
    Χρησιμοποιήστε χειρονομίες UP/DOWN ή τα κουμπιά
  </div>
</div>
</body>
</html>
)rawliteral";
  return html;
}

// ========== WEB SERVER ROUTES ==========
void setupWebServer() {
  server.on("/", []() {
    server.send(200, "text/html", getHTML());
  });
 
  server.on("/data", []() {
    String json = "{\"gesture\":\"" + lastGesture + "\",\"relay\":" + String(relayState) + "}";
    server.send(200, "application/json", json);
  });
 
  server.on("/relay", []() {
    if (server.hasArg("state")) {
      int state = server.arg("state").toInt();
      digitalWrite(RELAY_PIN, state);
      relayState = state;
      lastGesture = (state ? "Web ON" : "Web OFF");
      updateDisplay();
      beep(100);
      server.send(200, "text/plain", "OK");
    } else {
      server.send(400, "text/plain", "Missing param");
    }
  });
 
  server.begin();
  Serial.println("Web server started");
}

// ========== SETUP ==========
void setup() {
  Serial.begin(115200);
  Serial.println("Gesture System Starting...");
 
  // Ξεκινάμε I2C με χαμηλή ταχύτητα
  Wire.begin(21, 22);
  Wire.setClock(100000);  // 100 kHz
 
  // OLED αρχικοποίηση
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED failed!");
    while (true);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println("OLED Init OK");
  display.display();
  delay(1000);
 
  // Buzzer, Relay
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);
  relayState = LOW;
 
  // PAJ7620U2 με επαναφορές
  delay(500);
  int retry = 0;
  while (paj.begin() != 0 && retry < 5) {
    Serial.println("PAJ7620U2 not found! Retrying...");
    display.clearDisplay();
    display.println("PAJ Error");
    display.println("Retrying...");
    display.display();
    delay(2000);
    retry++;
  }
  if (retry == 5) {
    Serial.println("PAJ7620U2 failed permanently");
    display.println("PAJ Failed");
    display.display();
    while (true);
  }
  Serial.println("PAJ7620U2 OK");
  paj.setGestureHighRate(true);
 
  display.clearDisplay();
  display.println("PAJ OK");
  display.display();
  delay(500);
 
  // WiFi setup (όπως πριν)
  if (wifiMode == WIFI_MODE_AP) {
    WiFi.softAP("ARDicon_Gesture", "12345678");
    Serial.print("AP IP: ");
    Serial.println(WiFi.softAPIP());
    display.clearDisplay();
    display.println("AP Mode");
    display.println(WiFi.softAPIP());
    display.display();
  } else {
    WiFi.begin(ssid, password);
    display.clearDisplay();
    display.println("Connecting WiFi");
    display.display();
    int attempts = 0;
    while (WiFi.status() != WL_CONNECTED && attempts < 40) {
      delay(500);
      Serial.print(".");
      attempts++;
    }
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("\nConnected IP: " + WiFi.localIP().toString());
      display.clearDisplay();
      display.println("Connected");
      display.println(WiFi.localIP());
      display.display();
    } else {
      Serial.println("\nWiFi Failed");
      display.println("WiFi Error");
      display.display();
      while (true);
    }
  }
 
  setupWebServer();
  delay(1000);
  updateDisplay();
  beep(200, 2500);
  Serial.println("Ready.");
}

// ========== LOOP ==========
void loop() {
  server.handleClient();
 
  // Ανίχνευση χειρονομίας
  DFRobot_PAJ7620U2::eGesture_t gesture = paj.getGesture();
  if (gesture != paj.eGestureNone && (millis() - lastGestureTime > debounceTime)) {
    lastGestureTime = millis();
    String g = gestureToString(gesture);
    Serial.print("Gesture: ");
    Serial.println(g);
    handleGesture(gesture);
  }
 
  delay(30); // μικρή καθυστέρηση για σταθερότητα
}