#include "utilities.h"

#define TINY_GSM_DEBUG SerialMon
#define SerialMon Serial

#include <TinyGsmClient.h>
#include <StreamDebugger.h>

StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);

#define PIN_MICROSWITCH 0
#define PIN_TRAINING_SWITCH 1
#define PIN_BUZZER 2
#define PIN_LED 15

const char* smsTargets[] = {
  "+32XXXXXXXXX",  // Contact person 1
  "+32XXXXXXXXX"   // Contact person 2
};

// ---------------- Functions ----------------
void buzzAndBlink(int times, int duration_ms) {
    for (int i = 0; i < times; i++) {
        digitalWrite(PIN_BUZZER, HIGH);
        digitalWrite(PIN_LED, HIGH);
        delay(duration_ms / (2 * times));
        digitalWrite(PIN_BUZZER, LOW);
        digitalWrite(PIN_LED, LOW);
        delay(duration_ms / (2 * times));
    }
}

void buzzerCycleTwoMinutes() {
    unsigned long startTime = millis();
    while (millis() - startTime < 180000) {  //even op 30sec gezet om snel te kunnen testen!
        digitalWrite(PIN_BUZZER, HIGH);
        delay(100);
        digitalWrite(PIN_BUZZER, LOW);
        delay(200);
        digitalWrite(PIN_BUZZER, HIGH);
        delay(100);
        digitalWrite(PIN_BUZZER, LOW);
        delay(800);
    }
}

bool isKnownSender(String sender) {
    sender.trim();
    for (int i = 0; i < sizeof(smsTargets)/sizeof(smsTargets[0]); i++) {
        if (sender == smsTargets[i]) return true;
    }
    return false;
}

// ---------------- Setup ----------------
void setup() {
    Serial.begin(115200);
    randomSeed(analogRead(0)); // voor random bevestigingscode

    pinMode(PIN_MICROSWITCH, INPUT_PULLUP);
    pinMode(PIN_TRAINING_SWITCH, INPUT_PULLUP);
    pinMode(PIN_BUZZER, OUTPUT);
    pinMode(PIN_LED, OUTPUT);

    esp_sleep_enable_ext0_wakeup((gpio_num_t)PIN_MICROSWITCH, 0);

    if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
        bool trainingMode = digitalRead(PIN_TRAINING_SWITCH) == HIGH;

        // --- Training feedback ---
        buzzAndBlink(5, 3000);

        if (trainingMode) {
            Serial.println("Training mode: geen SMS verzonden.");
            modem.poweroff();
            digitalWrite(MODEM_DTR_PIN, HIGH);
            SerialAT.end();
            delay(100);
            esp_deep_sleep_start();
        }

        // --- Live mode ---
        Serial.println("Live mode: modem opstarten...");

        pinMode(MODEM_DTR_PIN, OUTPUT);
        digitalWrite(MODEM_DTR_PIN, LOW);

        pinMode(BOARD_PWRKEY_PIN, OUTPUT);
        digitalWrite(BOARD_PWRKEY_PIN, LOW);
        delay(100);
        digitalWrite(BOARD_PWRKEY_PIN, HIGH);
        delay(MODEM_POWERON_PULSE_WIDTH_MS);
        digitalWrite(BOARD_PWRKEY_PIN, LOW);

        SerialAT.begin(115200, SERIAL_8N1, MODEM_RX_PIN, MODEM_TX_PIN);
        delay(3000);
        while (!modem.testAT()) delay(10);

        // --- Modem configuratie ---
        SerialAT.println("AT+CMGF=1");       // SMS tekstmodus
        delay(100);
        SerialAT.println("AT+CSCS=\"GSM\""); // Charset
        delay(100);
        SerialAT.println("AT+CNMI=2,1,0,0,0"); // Event mode
        delay(100);

        // Wis oude SMS
        SerialAT.println("AT+CMGDA=\"DEL ALL\"");
        delay(500);

        modem.enableGPS(MODEM_GPS_ENABLE_GPIO, MODEM_GPS_ENABLE_LEVEL);
        modem.setGPSBaud(115200);

        // Wacht op netwerk registratie
        RegStatus status = REG_NO_RESULT;
        while (status == REG_NO_RESULT || status == REG_SEARCHING || status == REG_UNREGISTERED) {
            status = modem.getRegistrationStatus();
            delay(1000);
        }

        // GPS fix proberen
        float lat, lon; int vsat, usat; int year, month, day, hour, min, sec;
        uint8_t fixMode;
        bool gotFix = false;
        unsigned long gpsStart = millis();
        while (millis() - gpsStart < 60000) {
            if (modem.getGPS(&fixMode, &lat, &lon, NULL, NULL, &vsat, &usat, NULL,
                             &year, &month, &day, &hour, &min, &sec)) {
                gotFix = true;
                break;
            }
            delay(2000);
        }

        // Genereer random bevestigingscode
        int confirmCode = random(100, 1000);

        // Bouw SMS bericht met code
        String msg;
        if (gotFix) {
            msg = "https://www.openstreetmap.org/?mlat=" + String(lat,6) +
                  "&mlon=" + String(lon,6) + "#map=19/" + String(lat,6) + "/" + String(lon,6) +
                  "\nHulp gevraagd!\nStuur bevestigingscode: " + String(confirmCode);
        } else {
            msg = "Hulp gevraagd! Locatie niet beschikbaar.\nStuur bevestigingscode: " + String(confirmCode);
        }

        Serial.println("SMS: " + msg);
        for (int i=0; i<sizeof(smsTargets)/sizeof(smsTargets[0]); i++) {
            modem.sendSMS(smsTargets[i], msg);
        }

        // LED feedback 12s
        digitalWrite(PIN_LED, HIGH);
        delay(12000);
        digitalWrite(PIN_LED, LOW);

        // --- 5 minuten luisteren naar bevestigingscode ---
        Serial.println("⏳ Modem 5 minuten actief voor bevestigingscode...");
        unsigned long listenStart = millis();
        bool smsConfirmed = false;

        while (millis() - listenStart < 300000) { // 5 minuten
            SerialAT.println("AT+CMGL=\"REC UNREAD\""); // lijst ongelezen SMS
            delay(500);

            String response = "";
            unsigned long readStart = millis();
            while (millis() - readStart < 1000) {
                while (SerialAT.available()) {
                    String line = SerialAT.readStringUntil('\n');
                    line.trim();
                    if (line.length() > 0) response += line + "\n";
                }
            }

            // Parse SMS regels
            int idx = 0;
            while ((idx = response.indexOf("+CMGL:")) != -1) {
                int endLine = response.indexOf('\n', idx);
                String header = response.substring(idx, endLine);
                response = response.substring(endLine + 1);

                // Extract SMS index & sender
                int comma1 = header.indexOf(',');
                int comma2 = header.indexOf(',', comma1+1);
                int quote1 = header.indexOf('"', comma1);
                int quote2 = header.indexOf('"', quote1+1);
                int quote3 = header.indexOf('"', quote2+1);
                int quote4 = header.indexOf('"', quote3+1);

                int smsIndex = header.substring(7, comma1).toInt();
                String sender = header.substring(quote3+1, quote4);

                if (isKnownSender(sender)) {
                    // Lees SMS-bericht inhoud
                    SerialAT.print("AT+CMGRD=");
                    SerialAT.println(smsIndex);
                    delay(200);

                    String smsContent = "";
                    unsigned long contentStart = millis();
                    while (millis() - contentStart < 500) {
                        while (SerialAT.available()) {
                            String l = SerialAT.readStringUntil('\n');
                            l.trim();
                            if (l.length() > 0) smsContent += l;
                        }
                    }

                    // Check of smsContent exact de code bevat
                    if (smsContent.indexOf(String(confirmCode)) != -1) {
                        Serial.println("✅ Bevestigingscode ontvangen, buzzer starten!");
                        smsConfirmed = true;

                        // SMS verwijderen
                        SerialAT.print("AT+CMGD=");
                        SerialAT.println(smsIndex);
                        delay(100);

                        break;
                    }
                }
            }

            if (smsConfirmed) break;
            delay(2000); // 2 sec tussen polls
        }

        if (smsConfirmed) buzzerCycleTwoMinutes();

        modem.poweroff();
        digitalWrite(MODEM_DTR_PIN, HIGH);
        SerialAT.end();
    }

    // --- Terug naar deep sleep ---
    delay(100);
    esp_deep_sleep_start();
}

void loop() {}
