/*
 * Ολοκληρωμένο Σύστημα Ελέγχου Κλίματος
 * ARD:icon II IoT - DHT11 + OLED + 2xRelay + Buzzer + Web Server
 */

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

// ========== ΡΥΘΜΙΣΕΙΣ WiFi ==========
const char* ssid = "Redmi";
const char* password = "12345678";

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

// ========== DHT11 ==========
#define DHTPIN 33
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

// ========== ΕΞΟΔΟΙ ==========
#define BUZZER_PIN 5
#define RELAY_HEAT_PIN 16
#define RELAY_COOL_PIN 17

// ========== ΟΡΙΑ ΛΕΙΤΟΥΡΓΙΑΣ ==========
const float TEMP_LOW = 18.0;
const float TEMP_HIGH = 28.0;
const float ALARM_LOW = 13.0;
const float ALARM_HIGH = 33.0;

// ========== ΜΕΤΑΒΛΗΤΕΣ ==========
float temperature = 0.0;
float humidity = 0.0;
unsigned long lastRead = 0;
const long readInterval = 2000;
bool manualOverride = false;
bool manualHeat = false;
bool manualCool = false;

WebServer server(80);

// ========== 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>ARD:icon II Climate Control</title>
  <style>
    body { font-family: 'Segoe UI', Arial; text-align: center; background: linear-gradient(135deg, #1e3c72, #2a5298); margin: 0; padding: 20px; color: white; }
    .container { max-width: 700px; margin: 0 auto; background: rgba(255,255,255,0.1); backdrop-filter: blur(10px); padding: 25px; border-radius: 30px; box-shadow: 0 8px 20px rgba(0,0,0,0.3); }
    h1 { font-size: 28px; margin-bottom: 5px; }
    h2 { font-size: 18px; font-weight: normal; opacity: 0.9; margin-top: 0; }
    .sensor-box { background: rgba(0,0,0,0.3); border-radius: 20px; padding: 20px; margin: 20px 0; display: flex; justify-content: space-around; flex-wrap: wrap; }
    .sensor { font-size: 28px; margin: 10px; }
    .sensor span { font-weight: bold; background: rgba(255,255,255,0.2); padding: 8px 15px; border-radius: 50px; }
    .unit { font-size: 16px; }
    .status { background: #ff8c00; border-radius: 20px; padding: 15px; margin: 20px 0; font-weight: bold; }
    .relay-buttons { display: flex; gap: 15px; justify-content: center; margin: 20px 0; }
    button { background: #2ecc71; border: none; padding: 12px 25px; font-size: 16px; border-radius: 50px; cursor: pointer; font-weight: bold; transition: 0.2s; }
    button:hover { transform: scale(1.05); opacity: 0.9; }
    .btn-off { background: #e74c3c; }
    .btn-auto { background: #3498db; }
    .footer { font-size: 12px; margin-top: 20px; opacity: 0.7; }
    .alarm { color: #ff4444; animation: blink 1s infinite; }
    @keyframes blink { 50% { opacity: 0.5; } }
  </style>
  <script>
    function fetchData() {
      fetch('/data')
        .then(response => response.json())
        .then(data => {
          document.getElementById('temp').innerHTML = data.temp.toFixed(1);
          document.getElementById('hum').innerHTML = data.hum.toFixed(1);
          document.getElementById('heatStatus').innerHTML = data.heat ? 'ON 🔥' : 'OFF ❄️';
          document.getElementById('coolStatus').innerHTML = data.cool ? 'ON 💨' : 'OFF ⚪';
          document.getElementById('autoMode').innerHTML = data.auto ? 'AUTO ✓' : 'MANUAL';
          let alarmDiv = document.getElementById('alarmMsg');
          if (data.alarm) alarmDiv.innerHTML = '⚠️ ΑΚΡΑΙΑ ΘΕΡΜΟΚΡΑΣΙΑ! ⚠️';
          else alarmDiv.innerHTML = 'Κανονική λειτουργία';
        })
        .catch(err => console.log('Error:', err));
    }
    function setMode(auto) {
      fetch('/mode?auto=' + auto)
        .then(() => fetchData());
    }
    function setRelay(relay, state) {
      fetch('/relay?r=' + relay + '&s=' + state)
        .then(() => fetchData());
    }
    setInterval(fetchData, 2000);
    window.onload = fetchData;
  </script>
</head>
<body>
<div class='container'>
  <h1>ARD:icon II IoT</h1>
  <h2>Σύστημα Ελέγχου Κλίματος</h2>
  <div class='sensor-box'>
    <div class='sensor'>🌡️ Θερμοκρασία: <span id='temp'>--</span> <span class='unit'>°C</span></div>
    <div class='sensor'>💧 Υγρασία: <span id='hum'>--</span> <span class='unit'>%</span></div>
  </div>
  <div class='status'>
    Θέρμανση: <span id='heatStatus'>--</span> &nbsp;|&nbsp; Ψύξη: <span id='coolStatus'>--</span><br>
    Λειτουργία: <span id='autoMode'>--</span>
  </div>
  <div id='alarmMsg' class='alarm'></div>
  <div class='relay-buttons'>
    <button onclick='setMode(true)'>🤖 AUTO</button>
    <button onclick='setMode(false)'>✋ MANUAL</button>
  </div>
  <div class='relay-buttons'>
    <button class='btn-off' onclick='setRelay("heat",1)'>🔥 Heat ON</button>
    <button class='btn-off' onclick='setRelay("heat",0)'>🔥 Heat OFF</button>
    <button class='btn-off' onclick='setRelay("cool",1)'>❄️ Cool ON</button>
    <button class='btn-off' onclick='setRelay("cool",0)'>❄️ Cool OFF</button>
  </div>
  <div class='footer'>Live ανανέωση κάθε 2 sec | 1ο ΕΠΑΛ Συκεών</div>
</div>
</body>
</html>
)rawliteral";
  return html;
}

// ========== ΑΝΑΓΝΩΣΗ DHT11 ==========
void readSensor() {
  if (millis() - lastRead >= readInterval) {
    float h = dht.readHumidity();
    float t = dht.readTemperature();
    if (!isnan(h) && !isnan(t)) {
      humidity = h;
      temperature = t;
      Serial.print("Temp: "); Serial.print(temperature); Serial.print("°C  Hum: "); Serial.println(humidity);
    } else {
      Serial.println("DHT read error");
    }
    lastRead = millis();
  }
}

// ========== ΕΛΕΓΧΟΣ ΡΕΛΕ & BUZZER ==========
void controlSystem() {
  if (!manualOverride) {
    if (temperature < TEMP_LOW) {
      digitalWrite(RELAY_HEAT_PIN, HIGH);
      digitalWrite(RELAY_COOL_PIN, LOW);
    } else if (temperature > TEMP_HIGH) {
      digitalWrite(RELAY_HEAT_PIN, LOW);
      digitalWrite(RELAY_COOL_PIN, HIGH);
    } else {
      digitalWrite(RELAY_HEAT_PIN, LOW);
      digitalWrite(RELAY_COOL_PIN, LOW);
    }
  } else {
    // manual mode: τα ρελέ ελέγχονται μόνο από τα API calls
  }
 
  // Συναγερμός
  if (temperature < ALARM_LOW || temperature > ALARM_HIGH) {
    static unsigned long lastBuzzer = 0;
    if (millis() - lastBuzzer > 5000) {
      for (int i = 0; i < 3; i++) {
        tone(BUZZER_PIN, 2000);
        delay(200);
        noTone(BUZZER_PIN);
        delay(100);
      }
      lastBuzzer = millis();
    }
  } else {
    noTone(BUZZER_PIN);
  }
}

// ========== ΕΝΗΜΕΡΩΣΗ OLED ==========
void updateDisplay() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("=== CLIMATE CTRL ===");
  display.setTextSize(2);
  display.setCursor(0, 18);
  display.print(temperature, 1);
  display.println(" C");
  display.setTextSize(1);
  display.setCursor(0, 42);
  display.print("Hum: ");
  display.print(humidity, 1);
  display.println("%");
  display.setCursor(0, 52);
  if (digitalRead(RELAY_HEAT_PIN) == HIGH)
    display.println("HEAT ON ");
  else if (digitalRead(RELAY_COOL_PIN) == HIGH)
    display.println("COOL ON");
  else
    display.println("IDLE   ");
  display.display();
}

// ========== WEB SERVER ROUTES ==========
void setupWebServer() {
  server.on("/", []() {
    server.send(200, "text/html", getHTML());
  });
 
  server.on("/data", []() {
    bool heatState = digitalRead(RELAY_HEAT_PIN);
    bool coolState = digitalRead(RELAY_COOL_PIN);
    bool alarm = (temperature < ALARM_LOW || temperature > ALARM_HIGH);
    String json = "{\"temp\":" + String(temperature) +
                  ",\"hum\":" + String(humidity) +
                  ",\"heat\":" + String(heatState) +
                  ",\"cool\":" + String(coolState) +
                  ",\"auto\":" + String(!manualOverride) +
                  ",\"alarm\":" + String(alarm) + "}";
    server.send(200, "application/json", json);
  });
 
  // ΔΙΟΡΘΩΜΕΝΟΣ /mode (χωρίς auto keyword)
  server.on("/mode", []() {
    if (server.hasArg("auto")) {
      int autoModeVal = server.arg("auto").toInt();
      manualOverride = (autoModeVal == 0);
      if (manualOverride) {
        digitalWrite(RELAY_HEAT_PIN, LOW);
        digitalWrite(RELAY_COOL_PIN, LOW);
        manualHeat = false;
        manualCool = false;
      }
      server.send(200, "text/plain", "OK");
    } else {
      server.send(400, "text/plain", "Missing param");
    }
  });
 
  server.on("/relay", []() {
    if (manualOverride && server.hasArg("r") && server.hasArg("s")) {
      String relay = server.arg("r");
      int state = server.arg("s").toInt();
      if (relay == "heat") {
        digitalWrite(RELAY_HEAT_PIN, state);
        manualHeat = state;
      } else if (relay == "cool") {
        digitalWrite(RELAY_COOL_PIN, state);
        manualCool = state;
      }
      server.send(200, "text/plain", "OK");
    } else if (!manualOverride) {
      server.send(403, "text/plain", "Not in manual mode");
    } else {
      server.send(400, "text/plain", "Bad request");
    }
  });
 
  server.begin();
  Serial.println("Web server started");
}

// ========== SETUP ==========
void setup() {
  Serial.begin(115200);
 
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED failed");
    while (true);
  }
  display.clearDisplay();
  display.println("Booting...");
  display.display();
 
  dht.begin();
 
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(RELAY_HEAT_PIN, OUTPUT);
  pinMode(RELAY_COOL_PIN, OUTPUT);
  digitalWrite(RELAY_HEAT_PIN, LOW);
  digitalWrite(RELAY_COOL_PIN, LOW);
 
  WiFi.begin(ssid, password);
  display.clearDisplay();
  display.setCursor(0,0);
  display.print("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.setCursor(0,0);
    display.print("IP: ");
    display.println(WiFi.localIP().toString());
    display.display();
    delay(2000);
  } else {
    Serial.println("\nWiFi Failed");
    display.println("WiFi Error");
    display.display();
    while (true);
  }
 
  setupWebServer();
  display.clearDisplay();
}

// ========== LOOP ==========
void loop() {
  server.handleClient();
  readSensor();
  controlSystem();
  updateDisplay();
  delay(50);
}