#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>
#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"

// --- 1. KONFIGURASI WIFI & SERVER ---
const char* ssid = "xieqa_router";
const char* password = "11111111";
const char* host = "xieqa.com";
String apiKey = "sk-iot-d071690f8c42745892a05dda5da0fb89";
String id_jantung = "sensor_jantung";

// --- 2. OBJEK SENSOR & VARIABEL ---
MAX30105 particleSensor;

const byte RATE_SIZE = 10; // Ukuran buffer untuk stabilitas industri
byte rates[RATE_SIZE];
byte rateSpot = 0;
long lastBeat = 0;
float beatsPerMinute;
int beatAvg = 0;
bool fingerDetected = false;
byte validBeats = 0; // [OPTIMASI]: Pelacak jumlah data valid untuk mencegah Cold Start

// --- 3. VARIABEL KALIBRASI (OPTIMASI INDUSTRI) ---
const long FINGER_THRESHOLD = 40000; // Ambang batas deteksi jari
byte ledBrightness = 0x3C;  // 60 (Sekitar 12mA) untuk penetrasi kulit lebih baik
byte sampleAverage = 1;     // No averaging untuk raw data cepat
byte ledMode = 2;           // Red + IR
int sampleRate = 400;       // 400Hz: Standar emas untuk Pulse Oximetry
int pulseWidth = 411;       
int adcRange = 4096;

// Timer Non-Blocking
unsigned long lastSend = 0;
const long interval = 5000; // Kirim tiap 5 detik

void setup() {
  Serial.begin(115200);
  
  // Optimasi I2C Bus ke 400kHz untuk komunikasi sensor super cepat
  Wire.begin(4, 5); 
  Wire.setClock(400000);

  // WiFi Setup
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi Connected!");

  // Init Sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
    Serial.println("MAX30105 tidak ditemukan! Cek kabel SDA/SCL.");
    while (1); // Berhenti di sini jika sensor gagal
  }

  // --- KALIBRASI HARDWARE ---
  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);
  particleSensor.setPulseAmplitudeGreen(0); // Matikan LED Hijau (karena hanya butuh Red & IR)
  
  Serial.println("Sistem Siap. Tempelkan jari...");
}

void loop() {
  // Ambil nilai IR secara terus-menerus (Prioritas Utama)
  long irValue = particleSensor.getIR();

  // 1. Logika Deteksi Jari & Detak Jantung
  if (irValue > FINGER_THRESHOLD) {
    if (checkForBeat(irValue) == true) {
      long delta = millis() - lastBeat;
      lastBeat = millis();

      beatsPerMinute = 60 / (delta / 1000.0);

      // Filter BPM Fisiologis Manusia (40 - 180)
      if (beatsPerMinute < 180 && beatsPerMinute > 40) {
        rates[rateSpot++] = (byte)beatsPerMinute;
        rateSpot %= RATE_SIZE;

        // [OPTIMASI]: Tambah hitungan validBeats sampai batas RATE_SIZE
        if (validBeats < RATE_SIZE) validBeats++;

        // Hitung Rata-rata Bergerak Dinamis (Dynamic Moving Average)
        beatAvg = 0;
        for (byte x = 0; x < validBeats; x++) { 
          beatAvg += rates[x]; // Hanya jumlahkan data yang sudah terisi
        }
        beatAvg /= validBeats; // Pembagi dinamis, bukan langsung dibagi 10

        Serial.printf("Status: Terdeteksi | BPM: %.1f | Avg: %d\n", beatsPerMinute, beatAvg);
      }
    }
    fingerDetected = true;

  } else {
    // [OPTIMASI]: Hard Reset saat jari dilepas agar tidak mengirim/menyimpan data sampah
    fingerDetected = false;
    beatAvg = 0;
    rateSpot = 0;
    validBeats = 0; // Reset pelacak data valid
    memset(rates, 0, sizeof(rates)); // Bersihkan sisa data memori di array
  }

  // 2. Logika Pengiriman Data (Non-Blocking Timer)
  // Data dikirim setiap 'interval' tanpa menghentikan loop sensor secara total
  if (millis() - lastSend > interval) {
    lastSend = millis();

    if (WiFi.status() == WL_CONNECTED) {
      // Hanya kirim jika jari terdeteksi & data masuk akal
      if (fingerDetected && beatAvg >= 40) {
        kirimData(id_jantung, String(beatAvg));
      }
    } else {
      // Jika Putus: Reconnect secara non-blocking di background
      Serial.println("[System] WiFi Terputus! Mencoba Reconnect...");
      WiFi.reconnect(); 
    }
  }
}

void kirimData(String devID, String nilai) {
  // Pengaman ekstra: jangan kirim nilai tidak wajar
  if (nilai.toInt() < 40) return;

  WiFiClientSecure client;
  client.setInsecure(); // Mengabaikan validasi SSL untuk kecepatan & hemat memori ESP8266
  
  HTTPClient http;

  // Konstruksi URL API Gateway
  String url = "https://" + String(host) + "/ai/api/iot_gateway.php?k=" + apiKey + "&d=" + devID + "&v=" + nilai;
  
  // Timeout sangat pendek (1.5 detik) agar jika server sibuk, eksekusi MAX30105 tidak terganggu
  http.setTimeout(1500);

  if (http.begin(client, url)) {
    int httpCode = http.GET();

    if (httpCode > 0) {
      Serial.printf("[Cloud] Terkirim BPM: %s (Code: %d)\n", nilai.c_str(), httpCode);
    } else {
      Serial.printf("[Error] HTTP Gagal: %s\n", http.errorToString(httpCode).c_str());
    }
    http.end();
  }
}
