#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_AHTX0.h>
#include <TM1637Display.h>

const char* ssid = "computing";
const char* password = "1234567890";

String serverURL = "https://flamingorovers.lance.co.ke/dustbin/api/update_bin.php";

#define TRIG_PIN 5
#define ECHO_PIN 18

#define SDA_PIN 21
#define SCL_PIN 22
Adafruit_AHTX0 aht;

#define CLK 27
#define DIO 26
TM1637Display display(CLK, DIO);

float EMPTY_DISTANCE_CM = 21.7;
float FULL_DISTANCE_CM  = 5.0;

unsigned long lastWiFiTry = 0;
const unsigned long wifiRetryInterval = 10000;

unsigned long lastUpload = 0;
const unsigned long uploadInterval = 1000;

void startWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.setAutoReconnect(true);
  WiFi.persistent(false);
  WiFi.begin(ssid, password);
  Serial.println("WiFi connecting in background...");
}

void checkWiFi() {
  if (WiFi.status() == WL_CONNECTED) return;

  if (millis() - lastWiFiTry >= wifiRetryInterval) {
    lastWiFiTry = millis();
    Serial.println("Retrying WiFi...");
    WiFi.disconnect();
    WiFi.begin(ssid, password);
  }
}

float readDistanceCM() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 30000);
  if (duration == 0) return EMPTY_DISTANCE_CM;

  return duration * 0.0343 / 2;
}

int calculateFillLevel(float distance) {
  int level = map(distance * 10, EMPTY_DISTANCE_CM * 10, FULL_DISTANCE_CM * 10, 0, 100);
  if (level < 0) level = 0;
  if (level > 100) level = 100;
  return level;
}

void sendToServer(int level, float temp, float hum) {
  if (WiFi.status() != WL_CONNECTED) return;

  HTTPClient http;

  String url = serverURL +
               "?bin_id=ECO001" +
               "&level=" + String(level) +
               "&temperature=" + String(temp, 1) +
               "&humidity=" + String(hum, 1);

  Serial.println("Sending to:");
  Serial.println(url);

  http.begin(url);
  http.setTimeout(5000);

  int httpCode = http.GET();
  Serial.print("HTTP Code: ");
  Serial.println(httpCode);

  if (httpCode > 0) {
    Serial.print("Server response: ");
    Serial.println(http.getString());
  } else {
    Serial.print("HTTP error: ");
    Serial.println(http.errorToString(httpCode));
  }

  http.end();
}

void setup() {
  Serial.begin(115200);

  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

  Wire.begin(SDA_PIN, SCL_PIN);

  display.setBrightness(7);
  display.showNumberDec(0);

  if (!aht.begin()) {
    Serial.println("AHT10 not found!");
  } else {
    Serial.println("AHT10 OK");
  }

  startWiFi();
}

void loop() {
  checkWiFi();

  float distance = readDistanceCM();
  int fillLevel = calculateFillLevel(distance);

  display.showNumberDec(fillLevel, false);

  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);

  Serial.print("Level: ");
  Serial.print(fillLevel);
  Serial.print("% | Temp: ");
  Serial.print(temp.temperature);
  Serial.print(" C | Humidity: ");
  Serial.print(humidity.relative_humidity);
  Serial.print(" % | WiFi: ");
  Serial.println(WiFi.status() == WL_CONNECTED ? "Connected" : "Not connected");

  if (WiFi.status() == WL_CONNECTED && millis() - lastUpload >= uploadInterval) {
    lastUpload = millis();
    sendToServer(fillLevel, temp.temperature, humidity.relative_humidity);
  }

  delay(200);
}
