#include <Arduino.h>
#include <TBeamLogger.h>
#include <TBeamStorage.h>

#ifndef BOARD_ID
#define BOARD_ID "UNKNOWN"
#endif

#ifndef NODE_LABEL
#define NODE_LABEL "Unknown"
#endif

namespace {

tbeam::TBeamStorage storage(Serial);
tbeam::TBeamLogger Log;

uint32_t sampleSeq = 0;
uint32_t lastSampleMs = 0;

void onStorageEvent(tbeam::SdEvent event, const char* message) {
  const char* label = "unknown";
  if (event == tbeam::SdEvent::NO_CARD) label = "no_card";
  if (event == tbeam::SdEvent::CARD_MOUNTED) label = "mounted";
  if (event == tbeam::SdEvent::CARD_REMOVED) label = "removed";
  Serial.printf("[storage-event] %s: %s\r\n", label, message ? message : "");
}

}  // namespace

void setup() {
  Serial.begin(115200);
  delay(1500);
  Serial.println();
  Serial.printf("storage_logger test boot board=%s label=%s\r\n", BOARD_ID, NODE_LABEL);

  tbeam::StorageConfig storageConfig;
  storageConfig.logDir = "/logs/storage_logger";
  storageConfig.enablePinDumps = false;

  const bool mounted = storage.begin(storageConfig, onStorageEvent);
  Log.begin(Serial, &storage);

  if (mounted && Log.openUniqueLog(BOARD_ID, ".csv")) {
    Log.printf("# test: storage_logger\r\n");
    Log.printf("# board_id: %s\r\n", BOARD_ID);
    Log.printf("# node_label: %s\r\n", NODE_LABEL);
    Log.printf("# log_path: %s\r\n", Log.currentLogPath());
    Log.println("seq,millis,sd_ready,free_heap");
    Log.flush();
    Serial.printf("Log opened: %s\r\n", Log.currentLogPath());
  } else {
    Serial.printf("Log open skipped: mounted=%s error=%s\r\n",
                  mounted ? "yes" : "no",
                  storage.lastError());
  }

  Serial.println("Initial SD listing:");
  storage.listFiles(Serial, "/logs", 3);
}

void loop() {
  storage.update();
  Log.update();

  if (storage.consumeMountedEvent() && !Log.storageReady()) {
    if (Log.openUniqueLog(BOARD_ID, ".csv")) {
      Log.println("seq,millis,sd_ready,free_heap");
      Log.flush();
      Serial.printf("Log reopened: %s\r\n", Log.currentLogPath());
    }
  }

  if (storage.consumeRemovedEvent()) {
    Serial.println("SD removed; continuing Serial-only logging");
  }

  const uint32_t now = millis();
  if ((uint32_t)(now - lastSampleMs) >= 1000) {
    lastSampleMs = now;
    Log.printf("%lu,%lu,%s,%lu\r\n",
               (unsigned long)sampleSeq++,
               (unsigned long)now,
               storage.ready() ? "yes" : "no",
               (unsigned long)ESP.getFreeHeap());
  }
}
