// 20260215 ChatGPT
// $Id$
// $HeadURL$

#include <Arduino.h>
#include <Wire.h>
#include <U8g2lib.h>
#include "StartupSdManager.h"
#include "tbeam_supreme_adapter.h"

#define STARTUP_SERIAL_DELAY_MS 5000
#ifndef OLED_SDA
#define OLED_SDA 17
#endif
#ifndef OLED_SCL
#define OLED_SCL 18
#endif
#ifndef OLED_ADDR
#define OLED_ADDR 0x3C
#endif

static const char* kRootTestFile = "/Exercise_07_test.txt";
static const char* kNestedDir = "/test/testsub1/testsubsub1";
static const char* kNestedTestFile = "/test/testsub1/testsubsub1/Exercise_07_test.txt";
static const char* kPayload = "This is a test";
static const uint32_t kPeriodicActionMs = 15000;

static U8G2_SH1106_128X64_NONAME_F_HW_I2C g_oled(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
static StartupSdManager g_sd(Serial);
static uint32_t g_lastPeriodicActionMs = 0;

static void oledShow3(const char* l1, const char* l2 = nullptr, const char* l3 = nullptr) {
  g_oled.clearBuffer();
  g_oled.setFont(u8g2_font_6x10_tf);
  if (l1) g_oled.drawUTF8(0, 16, l1);
  if (l2) g_oled.drawUTF8(0, 32, l2);
  if (l3) g_oled.drawUTF8(0, 48, l3);
  g_oled.sendBuffer();
}

static void onSdStatus(SdEvent event, const char* message) {
  Serial.printf("[SD-STATUS] %s\r\n", message);

  if (event == SdEvent::NO_CARD) {
    oledShow3("Missing SD card", "Please insert card", "to proceed");
  } else if (event == SdEvent::CARD_MOUNTED) {
    oledShow3("SD card ready", "Mounted OK");
  } else if (event == SdEvent::CARD_REMOVED) {
    oledShow3("SD card removed", "Please re-insert");
  }
}

static void runCardWorkflow() {
  g_sd.printCardInfo();

  if (!g_sd.rewriteFile(kRootTestFile, kPayload)) {
    Serial.println("Watcher action: root file write failed");
    return;
  }
  if (!g_sd.ensureDirRecursive(kNestedDir)) {
    Serial.println("Watcher action: directory creation failed");
    return;
  }
  if (!g_sd.rewriteFile(kNestedTestFile, kPayload)) {
    Serial.println("Watcher action: nested file write failed");
    return;
  }

  g_sd.permissionsDemo(kRootTestFile);
}

void setup() {
  Serial.begin(115200);
  Wire.begin(OLED_SDA, OLED_SCL);
  g_oled.setI2CAddress(OLED_ADDR << 1);
  g_oled.begin();
  oledShow3("Exercise 07", "SD startup watcher", "Booting...");

  Serial.println("[WATCHER: startup]");
  Serial.printf("Sleeping for %lu ms to allow Serial Monitor connection...\r\n",
                (unsigned long)STARTUP_SERIAL_DELAY_MS);
  delay(STARTUP_SERIAL_DELAY_MS);

  Serial.println();
  Serial.println("==================================================");
  Serial.println("Exercise 07: SD Startup Watcher (Library Harness)");
  Serial.println("==================================================");
  Serial.printf("Pins: CS=%d SCK=%d MISO=%d MOSI=%d\r\n",
                tbeam_supreme::sdCs(), tbeam_supreme::sdSck(),
                tbeam_supreme::sdMiso(), tbeam_supreme::sdMosi());
  Serial.printf("PMU I2C: SDA1=%d SCL1=%d\r\n",
                tbeam_supreme::i2cSda(), tbeam_supreme::i2cScl());
  Serial.println("Note: SD must be FAT16/FAT32 for Arduino SD library.\r\n");

  SdWatcherConfig cfg;
  cfg.enableSdRailCycle = true;
  cfg.enablePinDumps = true;
  cfg.startupWarmupMs = 1500;
  cfg.pollIntervalAbsentMs = 1000;
  cfg.pollIntervalMountedMs = 2000;
  cfg.fullScanIntervalMs = 10000;
  cfg.votesToPresent = 2;
  cfg.votesToAbsent = 5;

  if (!g_sd.begin(cfg, onSdStatus)) {
    Serial.println("ERROR: SD watcher init failed");
  }

  if (g_sd.isMounted()) {
    runCardWorkflow();
    g_lastPeriodicActionMs = millis();
  }
}

void loop() {
  g_sd.update();

  if (g_sd.consumeMountedEvent()) {
    runCardWorkflow();
    g_lastPeriodicActionMs = millis();
  }

  if (g_sd.consumeRemovedEvent()) {
    Serial.println("SD removed, waiting for re-insert...");
  }

  const uint32_t now = millis();
  if (g_sd.isMounted() && (uint32_t)(now - g_lastPeriodicActionMs) >= kPeriodicActionMs) {
    Serial.println("Watcher: periodic mounted check action");
    runCardWorkflow();
    g_lastPeriodicActionMs = now;
  }

  delay(10);
}
