#include "nfc.h"
#include <Arduino.h>
#include <Adafruit_PN532.h>
#include <ArduinoJson.h>
#include "config.h"
#include "website.h"
#include "api.h"
#include "esp_task_wdt.h"
#include "scale.h"
#include "bambu.h"
#include "main.h"

//Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);
Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);

TaskHandle_t RfidReaderTask;

JsonDocument rfidData;
String activeSpoolId = "";
String lastSpoolId = "";
String nfcJsonData = "";
bool tagProcessed = false;
volatile bool pauseBambuMqttTask = false;
volatile bool nfcReadingTaskSuspendRequest = false;
volatile bool nfcReadingTaskSuspendState = false;
volatile bool nfcWriteInProgress = false; // Prevent any tag operations during write

struct NfcWriteParameterType {
  bool tagType;
  char* payload;
};

volatile nfcReaderStateType nfcReaderState = NFC_IDLE;
// 0 = nicht gelesen
// 1 = erfolgreich gelesen
// 2 = fehler beim Lesen
// 3 = schreiben
// 4 = fehler beim Schreiben
// 5 = erfolgreich geschrieben
// 6 = reading
// ***** PN532

// ##### Funktionen für RFID #####
void payloadToJson(uint8_t *data) {
    const char* startJson = strchr((char*)data, '{');
    const char* endJson = strrchr((char*)data, '}');
  
    if (startJson && endJson && endJson > startJson) {
      String jsonString = String(startJson, endJson - startJson + 1);
      //Serial.print("Bereinigter JSON-String: ");
      //Serial.println(jsonString);
  
      // JSON-Dokument verarbeiten
      JsonDocument doc;  // Passen Sie die Größe an den JSON-Inhalt an
      DeserializationError error = deserializeJson(doc, jsonString);
  
      if (!error) {
        const char* color_hex = doc["color_hex"];
        const char* type = doc["type"];
        int min_temp = doc["min_temp"];
        int max_temp = doc["max_temp"];
        const char* brand = doc["brand"];

        Serial.println();
        Serial.println("-----------------");
        Serial.println("JSON-Parsed Data:");
        Serial.println(color_hex);
        Serial.println(type);
        Serial.println(min_temp);
        Serial.println(max_temp);
        Serial.println(brand);
        Serial.println("-----------------");
        Serial.println();
      } else {
        Serial.print("deserializeJson() failed: ");
        Serial.println(error.f_str());
      }

      doc.clear();
    } else {
        Serial.println("Kein gültiger JSON-Inhalt gefunden oder fehlerhafte Formatierung.");
        //writeJsonToTag("{\"version\":\"1.0\",\"protocol\":\"NFC\",\"color_hex\":\"#FFFFFF\",\"type\":\"Example\",\"min_temp\":10,\"max_temp\":30,\"brand\":\"BrandName\"}");
    }
  }

bool formatNdefTag() {
    uint8_t ndefInit[] = { 0x03, 0x00, 0xFE }; // NDEF Initialisierungsnachricht
    bool success = true;
    int pageOffset = 4; // Startseite für NDEF-Daten auf NTAG2xx
  
    Serial.println();
    Serial.println("Formatiere NDEF-Tag...");
  
    // Schreibe die Initialisierungsnachricht auf die ersten Seiten
    for (int i = 0; i < sizeof(ndefInit); i += 4) {
      if (!nfc.ntag2xx_WritePage(pageOffset + (i / 4), &ndefInit[i])) {
          success = false;
          break;
      }
    }
  
    return success;
}uint16_t readTagSize()
{
  uint8_t buffer[4];
  memset(buffer, 0, 4);
  nfc.ntag2xx_ReadPage(3, buffer);
  return buffer[2]*8;
}

String detectNtagType()
{
  // Read capability container from page 3 to determine exact NTAG type
  uint8_t ccBuffer[4];
  memset(ccBuffer, 0, 4);
  
  if (!nfc.ntag2xx_ReadPage(3, ccBuffer)) {
    Serial.println("Failed to read capability container");
    return "UNKNOWN";
  }

  // Also read configuration pages to get more info
  uint8_t configBuffer[4];
  memset(configBuffer, 0, 4);
  
  Serial.print("Capability Container: ");
  for (int i = 0; i < 4; i++) {
    if (ccBuffer[i] < 0x10) Serial.print("0");
    Serial.print(ccBuffer[i], HEX);
    Serial.print(" ");
  }
  Serial.println();

  // NTAG type detection based on capability container
  // CC[2] contains the data area size in bytes / 8
  uint16_t dataAreaSize = ccBuffer[2] * 8;
  
  Serial.print("Data area size from CC: ");
  Serial.println(dataAreaSize);

  // Try to read different configuration pages to determine exact type
  String tagType = "UNKNOWN";
  
  // Try to read page 41 (NTAG213 ends at page 39, so this should fail)
  uint8_t testBuffer[4];
  bool canReadPage41 = nfc.ntag2xx_ReadPage(41, testBuffer);
  
  // Try to read page 130 (NTAG215 ends at page 129, so this should fail for NTAG213/215)
  bool canReadPage130 = nfc.ntag2xx_ReadPage(130, testBuffer);

  if (dataAreaSize <= 180 && !canReadPage41) {
    tagType = "NTAG213";
    Serial.println("Detected: NTAG213 (cannot read beyond page 39)");
  } else if (dataAreaSize <= 540 && canReadPage41 && !canReadPage130) {
    tagType = "NTAG215";
    Serial.println("Detected: NTAG215 (can read page 41, cannot read page 130)");
  } else if (dataAreaSize <= 928 && canReadPage130) {
    tagType = "NTAG216";
    Serial.println("Detected: NTAG216 (can read page 130)");
  } else {
    // Fallback: use data area size from capability container
    if (dataAreaSize <= 180) {
      tagType = "NTAG213";
      Serial.println("Fallback detection: NTAG213 based on data area size");
    } else if (dataAreaSize <= 540) {
      tagType = "NTAG215";
      Serial.println("Fallback detection: NTAG215 based on data area size");
    } else {
      tagType = "NTAG216";
      Serial.println("Fallback detection: NTAG216 based on data area size");
    }
  }
  
  return tagType;
}

uint16_t getAvailableUserDataSize()
{
  String tagType = detectNtagType();
  uint16_t userDataSize = 0;
  
  if (tagType == "NTAG213") {
    // NTAG213: User data from page 4-39 (36 pages * 4 bytes = 144 bytes)
    userDataSize = 144;
    Serial.println("NTAG213 confirmed - 144 bytes user data available");
  } else if (tagType == "NTAG215") {
    // NTAG215: User data from page 4-129 (126 pages * 4 bytes = 504 bytes)
    userDataSize = 504;
    Serial.println("NTAG215 confirmed - 504 bytes user data available");
  } else if (tagType == "NTAG216") {
    // NTAG216: User data from page 4-225 (222 pages * 4 bytes = 888 bytes)
    userDataSize = 888;
    Serial.println("NTAG216 confirmed - 888 bytes user data available");
  } else {
    // Unknown tag type, use conservative estimate
    uint16_t tagSize = readTagSize();
    userDataSize = tagSize - 60; // Reserve 60 bytes for headers/config
    Serial.print("Unknown NTAG type, using conservative estimate: ");
    Serial.println(userDataSize);
  }
  
  return userDataSize;
}

uint16_t getMaxUserDataPages()
{
  String tagType = detectNtagType();
  uint16_t maxPages = 0;
  
  if (tagType == "NTAG213") {
    maxPages = 39; // Pages 4-39 are user data
  } else if (tagType == "NTAG215") {
    maxPages = 129; // Pages 4-129 are user data
  } else if (tagType == "NTAG216") {
    maxPages = 225; // Pages 4-225 are user data
  } else {
    // Conservative fallback
    maxPages = 39;
    Serial.println("Unknown tag type, using NTAG213 page limit as fallback");
  }
  
  Serial.print("Maximum writable page: ");
  Serial.println(maxPages);
  return maxPages;
}

bool initializeNdefStructure() {
    // Write minimal NDEF structure without destroying the tag
    // This creates a clean slate while preserving tag functionality
    
    Serial.println("Initialisiere sichere NDEF-Struktur...");
    
    // Minimal NDEF structure: TLV with empty message
    uint8_t minimalNdef[8] = {
        0x03,           // NDEF Message TLV Tag
        0x03,           // Length (3 bytes for minimal empty record)
        0xD0,           // NDEF Record Header (TNF=0x0:Empty + SR + ME + MB)
        0x00,           // Type Length (0 = empty record)
        0x00,           // Payload Length (0 = empty record)
        0xFE,           // Terminator TLV
        0x00, 0x00      // Padding
    };
    
    // Write the minimal structure starting at page 4
    uint8_t pageBuffer[4];
    
    for (int i = 0; i < 8; i += 4) {
        memcpy(pageBuffer, &minimalNdef[i], 4);
        
        if (!nfc.ntag2xx_WritePage(4 + (i / 4), pageBuffer)) {
            Serial.print("Fehler beim Initialisieren von Seite ");
            Serial.println(4 + (i / 4));
            return false;
        }
        
        Serial.print("Seite ");
        Serial.print(4 + (i / 4));
        Serial.print(" initialisiert: ");
        for (int j = 0; j < 4; j++) {
            if (pageBuffer[j] < 0x10) Serial.print("0");
            Serial.print(pageBuffer[j], HEX);
            Serial.print(" ");
        }
        Serial.println();
    }
    
    Serial.println("✓ Sichere NDEF-Struktur initialisiert");
    Serial.println("✓ Tag bleibt funktionsfähig und überschreibbar");
    return true;
}

bool clearUserDataArea() {
    // IMPORTANT: Only clear user data pages, NOT configuration pages
    // NTAG layout: Pages 0-3 (header), 4-N (user data), N+1-N+3 (config) - NEVER touch config!
    String tagType = detectNtagType();
    
    // Calculate safe user data page ranges (NEVER touch config pages!)
    uint16_t firstUserPage = 4;
    uint16_t lastUserPage = 0;
    
    if (tagType == "NTAG213") {
        lastUserPage = 39;  // Pages 40-42 are config - DO NOT TOUCH!
        Serial.println("NTAG213: Sichere Löschung Seiten 4-39");
    } else if (tagType == "NTAG215") {
        lastUserPage = 129; // Pages 130-132 are config - DO NOT TOUCH!
        Serial.println("NTAG215: Sichere Löschung Seiten 4-129");
    } else if (tagType == "NTAG216") {
        lastUserPage = 225; // Pages 226-228 are config - DO NOT TOUCH!
        Serial.println("NTAG216: Sichere Löschung Seiten 4-225");
    } else {
        // Conservative fallback - only clear a small safe area
        lastUserPage = 39;
        Serial.println("UNKNOWN TAG: Konservative Löschung Seiten 4-39");
    }
    
    Serial.println("WARNUNG: Vollständiges Löschen kann Tag beschädigen!");
    Serial.println("Verwende stattdessen selective NDEF-Überschreibung...");
    
    // Instead of clearing everything, just write a minimal NDEF structure
    // This is much safer and preserves tag integrity
    return initializeNdefStructure();
}

uint8_t ntag2xx_WriteNDEF(const char *payload) {
  // Determine exact tag type and capabilities first
  String tagType = detectNtagType();
  uint16_t tagSize = readTagSize();
  uint16_t availableUserData = getAvailableUserDataSize();
  uint16_t maxWritablePage = getMaxUserDataPages();
  
  Serial.println("=== NFC TAG ANALYSIS ===");
  Serial.print("Tag Type: ");Serial.println(tagType);
  Serial.print("Total Tag Size: ");Serial.println(tagSize);
  Serial.print("Available User Data: ");Serial.println(availableUserData);
  Serial.print("Max Writable Page: ");Serial.println(maxWritablePage);
  Serial.println("========================");

  // Perform additional tag validation by testing write boundaries
  Serial.println("=== TAG VALIDATION ===");
  uint8_t testBuffer[4] = {0x00, 0x00, 0x00, 0x00};
  
  // Test if we can actually read the max page
  if (!nfc.ntag2xx_ReadPage(maxWritablePage, testBuffer)) {
    Serial.print("WARNING: Cannot read declared max page ");
    Serial.println(maxWritablePage);
    
    // Find actual maximum writable page by testing backwards with optimized approach
    uint16_t actualMaxPage = maxWritablePage;
    Serial.println("Searching for actual maximum writable page...");
    
    // Use binary search approach for faster page limit detection
    uint16_t lowPage = 4;
    uint16_t highPage = maxWritablePage;
    uint16_t testAttempts = 0;
    const uint16_t maxTestAttempts = 15; // Limit search attempts
    
    while (lowPage <= highPage && testAttempts < maxTestAttempts) {
      uint16_t midPage = (lowPage + highPage) / 2;
      testAttempts++;
      
      Serial.print("Testing page ");
      Serial.print(midPage);
      Serial.print(" (attempt ");
      Serial.print(testAttempts);
      Serial.print("/");
      Serial.print(maxTestAttempts);
      Serial.print(")... ");
      
      if (nfc.ntag2xx_ReadPage(midPage, testBuffer)) {
        Serial.println("✓");
        actualMaxPage = midPage;
        lowPage = midPage + 1; // Search higher
      } else {
        Serial.println("❌");
        highPage = midPage - 1; // Search lower
      }
      
      // Small delay to prevent interface overload
      vTaskDelay(5 / portTICK_PERIOD_MS);
      yield();
    }
    
    Serial.print("Found actual max readable page: ");
    Serial.println(actualMaxPage);
    Serial.print("Search completed in ");
    Serial.print(testAttempts);
    Serial.println(" attempts");
    
    maxWritablePage = actualMaxPage;
  } else {
    Serial.print("✓ Max page ");Serial.print(maxWritablePage);Serial.println(" is readable");
  }
  
  // Calculate maximum available user data based on actual writable pages
  uint16_t actualUserDataSize = (maxWritablePage - 3) * 4; // -3 because pages 0-3 are header
  availableUserData = actualUserDataSize;
  
  Serial.print("Actual available user data: ");
  Serial.print(actualUserDataSize);
  Serial.println(" bytes");
  Serial.println("========================");

  uint8_t pageBuffer[4] = {0, 0, 0, 0};
  Serial.println("Beginne mit dem Schreiben der NDEF-Nachricht...");
  
  // Figure out how long the string is
  uint16_t payloadLen = strlen(payload);
  Serial.print("Länge der Payload: ");
  Serial.println(payloadLen);
  
  Serial.print("Payload: ");Serial.println(payload);

  // MIME type for JSON
  const char mimeType[] = "application/json";
  uint8_t mimeTypeLen = strlen(mimeType);
  
  // Calculate NDEF record size
  uint8_t ndefRecordHeaderSize = 3; // Header byte + Type Length + Payload Length (short record)
  uint16_t ndefRecordSize = ndefRecordHeaderSize + mimeTypeLen + payloadLen;
  
  // Calculate TLV size - need to check if we need extended length format
  uint8_t tlvHeaderSize;
  uint16_t totalTlvSize;
  
  if (ndefRecordSize <= 254) {
    // Standard TLV format: Tag (1) + Length (1) + Value (ndefRecordSize)
    tlvHeaderSize = 2;
    totalTlvSize = tlvHeaderSize + ndefRecordSize + 1; // +1 for terminator TLV
  } else {
    // Extended TLV format: Tag (1) + 0xFF + Length (2) + Value (ndefRecordSize)  
    tlvHeaderSize = 4;
    totalTlvSize = tlvHeaderSize + ndefRecordSize + 1; // +1 for terminator TLV
  }

  Serial.print("NDEF Record Size: ");
  Serial.println(ndefRecordSize);
  Serial.print("Total TLV Size: ");
  Serial.println(totalTlvSize);

  // Check if the message fits in the available user data space
  if (totalTlvSize > availableUserData) {
    Serial.println();
    Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!");
    Serial.println("FEHLER: Payload zu groß für diesen Tag-Typ!");
    Serial.print("Tag-Typ: ");Serial.println(tagType);
    Serial.print("Benötigt: ");Serial.print(totalTlvSize);Serial.println(" Bytes");
    Serial.print("Verfügbar: ");Serial.print(availableUserData);Serial.println(" Bytes");
    Serial.print("Überschuss: ");Serial.print(totalTlvSize - availableUserData);Serial.println(" Bytes");
    
    if (tagType == "NTAG213") {
      Serial.println("EMPFEHLUNG: Verwenden Sie einen NTAG215 (504 Bytes) oder NTAG216 (888 Bytes) Tag!");
      Serial.println("Oder kürzen Sie die Payload um mindestens " + String(totalTlvSize - availableUserData) + " Bytes.");
    }
    Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!");
    Serial.println();
    
    oledShowMessage("Tag zu klein für Payload");
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    return 0;
  }

  Serial.println("✓ Payload passt in den Tag - Schreibvorgang wird fortgesetzt");

  // STEP 1: NFC Interface Reset and Reinitialization
  Serial.println();
  Serial.println("=== SCHRITT 1: NFC-INTERFACE RESET UND NEUINITIALISIERUNG ===");
  
  // First, check if the NFC interface is working at all
  Serial.println("Teste aktuellen NFC-Interface-Zustand...");
  
  // Try to read capability container (which worked during detection)
  uint8_t ccTest[4];
  bool ccReadable = nfc.ntag2xx_ReadPage(3, ccTest);
  Serial.print("Capability Container (Seite 3) lesbar: ");
  Serial.println(ccReadable ? "✓" : "❌");
  
  if (!ccReadable) {
    Serial.println("❌ NFC-Interface ist nicht funktionsfähig - führe Reset durch");
    
    // Perform NFC interface reset and reinitialization
    Serial.println("Führe NFC-Interface Reset durch...");
    
    // Step 1: Try to reinitialize the NFC interface completely
    Serial.println("1. Neuinitialisierung des PN532...");
    
    // Reinitialize the PN532
    nfc.begin();
    vTaskDelay(500 / portTICK_PERIOD_MS); // Give it time to initialize
    
    // Check firmware version to ensure communication is working
    uint32_t versiondata = nfc.getFirmwareVersion();
    if (versiondata) {
      Serial.print("PN532 Firmware Version: 0x");
      Serial.println(versiondata, HEX);
      Serial.println("✓ PN532 Kommunikation wiederhergestellt");
    } else {
      Serial.println("❌ PN532 Kommunikation fehlgeschlagen");
      oledShowMessage("NFC Reset failed");
      vTaskDelay(3000 / portTICK_PERIOD_MS);
      return 0;
    }
    
    // Step 2: Reconfigure SAM
    Serial.println("2. SAM-Konfiguration...");
    nfc.SAMConfig();
    vTaskDelay(200 / portTICK_PERIOD_MS);
    
    // Step 3: Re-detect the tag
    Serial.println("3. Tag-Wiedererkennung...");
    uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
    uint8_t uidLength;
    bool tagRedetected = false;
    
    for (int attempts = 0; attempts < 5; attempts++) {
      Serial.print("Tag-Erkennungsversuch ");
      Serial.print(attempts + 1);
      Serial.print("/5... ");
      
      if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000)) {
        Serial.println("✓");
        tagRedetected = true;
        break;
      } else {
        Serial.println("❌");
        vTaskDelay(300 / portTICK_PERIOD_MS);
      }
    }
    
    if (!tagRedetected) {
      Serial.println("❌ Tag konnte nach Reset nicht wiedererkannt werden");
      oledShowMessage("Tag lost after reset");
      vTaskDelay(3000 / portTICK_PERIOD_MS);
      return 0;
    }
    
    Serial.println("✓ Tag erfolgreich wiedererkannt");
    
    // Step 4: Test basic page reading
    Serial.println("4. Test der Grundfunktionalität...");
    vTaskDelay(200 / portTICK_PERIOD_MS); // Give interface time to stabilize
    
    ccReadable = nfc.ntag2xx_ReadPage(3, ccTest);
    Serial.print("Capability Container nach Reset lesbar: ");
    Serial.println(ccReadable ? "✓" : "❌");
    
    if (!ccReadable) {
      Serial.println("❌ NFC-Interface funktioniert nach Reset immer noch nicht");
      oledShowMessage("NFC still broken");
      vTaskDelay(3000 / portTICK_PERIOD_MS);
      return 0;
    }
    
    Serial.println("✓ NFC-Interface erfolgreich wiederhergestellt");
  } else {
    Serial.println("✓ NFC-Interface ist funktionsfähig");
  }
  
  // Display CC content for debugging
  if (ccReadable) {
    Serial.print("CC Inhalt: ");
    for (int i = 0; i < 4; i++) {
      if (ccTest[i] < 0x10) Serial.print("0");
      Serial.print(ccTest[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
  
  Serial.println("=== SCHRITT 2: INTERFACE-FUNKTIONSTEST ===");
  
  // Test a few critical pages to ensure stable operation
  uint8_t testData[4];
  bool basicPagesReadable = true;
  
  for (uint8_t testPage = 0; testPage <= 6; testPage++) {
    bool readable = nfc.ntag2xx_ReadPage(testPage, testData);
    Serial.print("Seite ");
    Serial.print(testPage);
    Serial.print(": ");
    if (readable) {
      Serial.print("✓ - ");
      for (int i = 0; i < 4; i++) {
        if (testData[i] < 0x10) Serial.print("0");
        Serial.print(testData[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    } else {
      Serial.println("❌ - Nicht lesbar");
      if (testPage >= 3 && testPage <= 6) { // Critical pages for NDEF
        basicPagesReadable = false;
      }
    }
    vTaskDelay(10 / portTICK_PERIOD_MS); // Small delay between reads
  }
  
  if (!basicPagesReadable) {
    Serial.println("❌ KRITISCHER FEHLER: Grundlegende NDEF-Seiten nicht lesbar!");
    Serial.println("Tag oder Interface ist defekt");
    oledShowMessage("Tag/Interface defect");
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    return 0;
  }
  
  Serial.println("✓ Alle kritischen Seiten sind lesbar");
  Serial.println("===================================================");

  Serial.println();
  Serial.println("=== SCHRITT 3: SCHREIBBEREITSCHAFTSTEST ===");
  
  // Test write capabilities before attempting the full write
  Serial.println("Teste Schreibfähigkeiten des Tags...");
  
  uint8_t testPage[4] = {0xAA, 0xBB, 0xCC, 0xDD}; // Test pattern
  uint8_t originalPage[4]; // Store original content
  
  // First, read original content of test page
  if (!nfc.ntag2xx_ReadPage(10, originalPage)) {
    Serial.println("FEHLER: Kann Testseite nicht lesen für Backup");
    oledShowMessage("Test page read error");
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    return 0;
  }
  
  Serial.print("Original Inhalt Seite 10: ");
  for (int i = 0; i < 4; i++) {
    if (originalPage[i] < 0x10) Serial.print("0");
    Serial.print(originalPage[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
  
  // Perform write test
  if (!nfc.ntag2xx_WritePage(10, testPage)) {
    Serial.println("FEHLER: Schreibtest fehlgeschlagen!");
    Serial.println("Tag ist möglicherweise schreibgeschützt oder defekt");
    
    // Additional diagnostics
    Serial.println("=== ERWEITERTE SCHREIBTEST-DIAGNOSE ===");
    
    // Check if tag is still present
    uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
    uint8_t uidLength;
    bool tagStillPresent = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000);
    Serial.print("Tag noch erkannt: ");
    Serial.println(tagStillPresent ? "✓" : "❌");
    
    if (!tagStillPresent) {
      Serial.println("URSACHE: Tag wurde während Schreibtest entfernt!");
      oledShowMessage("Tag removed");
    } else {
      Serial.println("URSACHE: Tag ist vorhanden aber nicht beschreibbar");
      Serial.println("Möglicherweise: Schreibschutz, Defekt, oder Interface-Problem");
      oledShowMessage("Tag write protected?");
    }
    Serial.println("==========================================");
    
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    return 0;
  }
  
  // Verify test write
  uint8_t readBack[4];
  vTaskDelay(20 / portTICK_PERIOD_MS); // Wait for write to complete
  
  if (!nfc.ntag2xx_ReadPage(10, readBack)) {
    Serial.println("FEHLER: Kann Testdaten nicht zurücklesen!");
    oledShowMessage("Test verify failed");
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    return 0;
  }
  
  bool testSuccess = true;
  for (int i = 0; i < 4; i++) {
    if (readBack[i] != testPage[i]) {
      testSuccess = false;
      break;
    }
  }
  
  if (!testSuccess) {
    Serial.println("FEHLER: Schreibtest fehlgeschlagen - Daten stimmen nicht überein!");
    Serial.print("Geschrieben: ");
    for (int i = 0; i < 4; i++) {
      Serial.print(testPage[i], HEX); Serial.print(" ");
    }
    Serial.println();
    Serial.print("Gelesen: ");
    for (int i = 0; i < 4; i++) {
      Serial.print(readBack[i], HEX); Serial.print(" ");
    }
    Serial.println();
    return 0;
  }
  
  // Restore original content
  Serial.println("Stelle ursprünglichen Inhalt wieder her...");
  if (!nfc.ntag2xx_WritePage(10, originalPage)) {
    Serial.println("WARNUNG: Konnte ursprünglichen Inhalt nicht wiederherstellen!");
  } else {
    Serial.println("✓ Ursprünglicher Inhalt wiederhergestellt");
  }
  
  Serial.println("✓ Schreibtest erfolgreich - Tag ist voll funktionsfähig");
  Serial.println("======================================================");

  // STEP 4: NDEF initialization with verification
  Serial.println();
  Serial.println("=== SCHRITT 4: NDEF-INITIALISIERUNG ===");
  if (!initializeNdefStructure()) {
    Serial.println("FEHLER: Konnte NDEF-Struktur nicht initialisieren!");
    oledShowMessage("NDEF init failed");
    vTaskDelay(2000 / portTICK_PERIOD_MS);
    return 0;
  }
  
  // Verify NDEF initialization
  uint8_t ndefCheck[8];
  bool ndefVerified = true;
  for (uint8_t page = 4; page < 6; page++) {
    if (!nfc.ntag2xx_ReadPage(page, &ndefCheck[(page-4)*4])) {
      ndefVerified = false;
      break;
    }
  }
  
  if (ndefVerified) {
    Serial.print("NDEF-Header nach Initialisierung: ");
    for (int i = 0; i < 8; i++) {
      if (ndefCheck[i] < 0x10) Serial.print("0");
      Serial.print(ndefCheck[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
  
  Serial.println("✓ NDEF-Struktur initialisiert und verifiziert");
  Serial.println("==========================================");

  // STEP 5: Allow interface to stabilize before major write operation
  Serial.println();
  Serial.println("=== SCHRITT 5: NFC-INTERFACE STABILISIERUNG ===");
  Serial.println("Stabilisiere NFC-Interface vor Hauptschreibvorgang...");
  
  // Give the interface time to fully settle after NDEF initialization
  vTaskDelay(200 / portTICK_PERIOD_MS);
  
  // Test interface stability with a simple read
  uint8_t stabilityTest[4];
  bool interfaceStable = false;
  for (int attempts = 0; attempts < 3; attempts++) {
    if (nfc.ntag2xx_ReadPage(4, stabilityTest)) {
      Serial.print("Interface stability test ");
      Serial.print(attempts + 1);
      Serial.println("/3: ✓");
      interfaceStable = true;
      break;
    } else {
      Serial.print("Interface stability test ");
      Serial.print(attempts + 1);
      Serial.println("/3: ❌");
      vTaskDelay(100 / portTICK_PERIOD_MS);
    }
  }
  
  if (!interfaceStable) {
    Serial.println("FEHLER: NFC-Interface ist nicht stabil genug für Schreibvorgang");
    oledShowMessage("NFC Interface unstable");
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    return 0;
  }
  
  Serial.println("✓ NFC-Interface ist stabil - Schreibvorgang kann beginnen");
  Serial.println("=========================================================");

  // Allocate memory for the complete TLV structure
  uint8_t* tlvData = (uint8_t*) malloc(totalTlvSize);
  if (tlvData == NULL) {
    Serial.println("Fehler: Nicht genug Speicher für TLV-Daten vorhanden.");
    oledShowMessage("Memory error");
    vTaskDelay(2000 / portTICK_PERIOD_MS);
    return 0;
  }

  // Build TLV structure
  uint16_t offset = 0;
  
  // TLV Header
  tlvData[offset++] = 0x03; // NDEF Message TLV Tag
  
  if (ndefRecordSize <= 254) {
    // Standard length format
    tlvData[offset++] = (uint8_t)ndefRecordSize;
  } else {
    // Extended length format
    tlvData[offset++] = 0xFF;
    tlvData[offset++] = (uint8_t)(ndefRecordSize >> 8);  // High byte
    tlvData[offset++] = (uint8_t)(ndefRecordSize & 0xFF); // Low byte
  }

  // NDEF Record Header
  tlvData[offset++] = 0xD2; // NDEF Record Header (TNF=0x2:MIME Media + SR + ME + MB)
  tlvData[offset++] = mimeTypeLen; // Type Length
  tlvData[offset++] = (uint8_t)payloadLen; // Payload Length (short record format)

  // MIME Type
  memcpy(&tlvData[offset], mimeType, mimeTypeLen);
  offset += mimeTypeLen;

  // JSON Payload
  memcpy(&tlvData[offset], payload, payloadLen);
  offset += payloadLen;

  // Terminator TLV
  tlvData[offset] = 0xFE;

  Serial.print("Gesamt-TLV-Länge: ");
  Serial.println(offset + 1);

  // Debug: Print first 64 bytes of TLV data
  Serial.println("TLV Daten (erste 64 Bytes):");
  for (int i = 0; i < min((int)(offset + 1), 64); i++) {
    if (tlvData[i] < 0x10) Serial.print("0");
    Serial.print(tlvData[i], HEX);
    Serial.print(" ");
    if ((i + 1) % 16 == 0) Serial.println();
  }
  Serial.println();

  // Write data to tag pages (starting from page 4)
  uint16_t bytesWritten = 0;
  uint8_t pageNumber = 4;
  uint16_t totalBytes = offset + 1;

  Serial.println();
  Serial.println("=== SCHRITT 6: SCHREIBE NEUE NDEF-DATEN ===");
  Serial.print("Schreibe ");
  Serial.print(totalBytes);
  Serial.print(" Bytes in ");
  Serial.print((totalBytes + 3) / 4); // Round up division
  Serial.println(" Seiten...");

  while (bytesWritten < totalBytes && pageNumber <= maxWritablePage) {
    // Additional safety check before writing each page
    if (pageNumber > maxWritablePage) {
      Serial.print("STOP: Reached maximum writable page ");
      Serial.println(maxWritablePage);
      break;
    }
    
    // Clear page buffer
    memset(pageBuffer, 0, 4);
    
    // Calculate how many bytes to write to this page
    uint16_t bytesToWrite = min(4, (int)(totalBytes - bytesWritten));
    
    // Copy data to page buffer
    memcpy(pageBuffer, &tlvData[bytesWritten], bytesToWrite);

    // Write page to tag with retry mechanism
    bool writeSuccess = false;
    for (int writeAttempt = 0; writeAttempt < 3; writeAttempt++) {
      if (nfc.ntag2xx_WritePage(pageNumber, pageBuffer)) {
        writeSuccess = true;
        break;
      } else {
        Serial.print("Schreibversuch ");
        Serial.print(writeAttempt + 1);
        Serial.print("/3 für Seite ");
        Serial.print(pageNumber);
        Serial.println(" fehlgeschlagen");
        
        if (writeAttempt < 2) {
          vTaskDelay(50 / portTICK_PERIOD_MS); // Wait before retry
        }
      }
    }

    if (!writeSuccess) {
      Serial.print("FEHLER beim Schreiben der Seite ");
      Serial.println(pageNumber);
      Serial.print("Möglicherweise Page-Limit erreicht für ");
      Serial.println(tagType);
      Serial.print("Erwartetes Maximum: ");
      Serial.println(maxWritablePage);
      Serial.print("Tatsächliches Maximum scheint niedriger zu sein!");
      
      // Update max page for future operations
      if (pageNumber > 4) {
        Serial.print("Setze neues Maximum auf Seite ");
        Serial.println(pageNumber - 1);
      }
      
      free(tlvData);
      return 0;
    }

    // IMMEDIATE verification after each write - this is critical!
    Serial.print("Verifiziere Seite ");
    Serial.print(pageNumber);
    Serial.print("... ");
    
    uint8_t verifyBuffer[4];
    vTaskDelay(20 / portTICK_PERIOD_MS); // Increased delay before verification
    
    // Verification with retry mechanism
    bool verifySuccess = false;
    for (int verifyAttempt = 0; verifyAttempt < 3; verifyAttempt++) {
      if (nfc.ntag2xx_ReadPage(pageNumber, verifyBuffer)) {
        bool writeMatches = true;
        for (int i = 0; i < bytesToWrite; i++) {
          if (verifyBuffer[i] != pageBuffer[i]) {
            writeMatches = false;
            Serial.println();
            Serial.print("VERIFIKATIONSFEHLER bei Byte ");
            Serial.print(i);
            Serial.print(" - Erwartet: 0x");
            Serial.print(pageBuffer[i], HEX);
            Serial.print(", Gelesen: 0x");
            Serial.println(verifyBuffer[i], HEX);
            break;
          }
        }
        
        if (writeMatches) {
          verifySuccess = true;
          break;
        } else if (verifyAttempt < 2) {
          Serial.print("Verifikationsversuch ");
          Serial.print(verifyAttempt + 1);
          Serial.println("/3 fehlgeschlagen, wiederhole...");
          vTaskDelay(30 / portTICK_PERIOD_MS);
        }
      } else {
        Serial.print("Verifikations-Read-Versuch ");
        Serial.print(verifyAttempt + 1);
        Serial.println("/3 fehlgeschlagen");
        if (verifyAttempt < 2) {
          vTaskDelay(30 / portTICK_PERIOD_MS);
        }
      }
    }
    
    if (!verifySuccess) {
      Serial.println("❌ SCHREIBVORGANG/VERIFIKATION FEHLGESCHLAGEN!");
      free(tlvData);
      return 0;
    } else {
      Serial.println("✓");
    }

    Serial.print("Seite ");
    Serial.print(pageNumber);
    Serial.print(" ✓: ");
    for (int i = 0; i < 4; i++) {
      if (pageBuffer[i] < 0x10) Serial.print("0");
      Serial.print(pageBuffer[i], HEX);
      Serial.print(" ");
    }
    Serial.println();

    bytesWritten += bytesToWrite;
    pageNumber++;
    
    yield();
    vTaskDelay(10 / portTICK_PERIOD_MS); // Slightly increased delay between page writes
  }

  free(tlvData);
  
  if (bytesWritten < totalBytes) {
    Serial.println("WARNUNG: Nicht alle Daten konnten geschrieben werden!");
    Serial.print("Geschrieben: ");
    Serial.print(bytesWritten);
    Serial.print(" von ");
    Serial.print(totalBytes);
    Serial.println(" Bytes");
    Serial.print("Gestoppt bei Seite: ");
    Serial.println(pageNumber - 1);
    return 0;
  }
  
  Serial.println();
  Serial.println("✓ NDEF-Nachricht erfolgreich geschrieben!");
  Serial.print("✓ Tag-Typ: ");Serial.println(tagType);
  Serial.print("✓ Insgesamt ");Serial.print(bytesWritten);Serial.println(" Bytes geschrieben");
  Serial.print("✓ Verwendete Seiten: 4-");Serial.println(pageNumber - 1);
  Serial.print("✓ Speicher-Auslastung: ");
  Serial.print((bytesWritten * 100) / availableUserData);
  Serial.println("%");
  Serial.println("✓ Bestehende Daten wurden überschrieben");
  
  // CRITICAL: Allow NFC interface to stabilize after write operation
  Serial.println();
  Serial.println("=== SCHRITT 7: NFC-INTERFACE STABILISIERUNG NACH SCHREIBVORGANG ===");
  Serial.println("Stabilisiere NFC-Interface nach Schreibvorgang...");
  
  // Give the tag and interface time to settle after write operation
  vTaskDelay(300 / portTICK_PERIOD_MS); // Increased stabilization time
  
  // Test if the interface is still responsive
  uint8_t postWriteTest[4];
  bool interfaceResponsive = false;
  
  for (int stabilityAttempt = 0; stabilityAttempt < 5; stabilityAttempt++) {
    Serial.print("Post-write interface test ");
    Serial.print(stabilityAttempt + 1);
    Serial.print("/5... ");
    
    if (nfc.ntag2xx_ReadPage(3, postWriteTest)) { // Read capability container
      Serial.println("✓");
      interfaceResponsive = true;
      break;
    } else {
      Serial.println("❌");
      
      if (stabilityAttempt < 4) {
        Serial.println("Warte und versuche Interface zu stabilisieren...");
        vTaskDelay(200 / portTICK_PERIOD_MS);
        
        // Try to re-establish communication with a simple tag presence check
        uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
        uint8_t uidLength;
        bool tagStillPresent = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000);
        Serial.print("Tag presence check: ");
        Serial.println(tagStillPresent ? "✓" : "❌");
        
        if (!tagStillPresent) {
          Serial.println("Tag wurde während/nach Schreibvorgang entfernt!");
          break;
        }
      }
    }
  }
  
  if (!interfaceResponsive) {
    Serial.println("WARNUNG: NFC-Interface reagiert nach Schreibvorgang nicht mehr stabil");
    Serial.println("Schreibvorgang war erfolgreich, aber Interface benötigt möglicherweise Reset");
  } else {
    Serial.println("✓ NFC-Interface ist nach Schreibvorgang stabil");
  }
  
  Serial.println("==================================================================");
  
  return 1;
}

bool decodeNdefAndReturnJson(const byte* encodedMessage, String uidString) {
  oledShowProgressBar(1, octoEnabled?5:4, "Reading", "Decoding data");

  // Debug: Print first 32 bytes of the raw data
  Serial.println("Raw NDEF data (first 32 bytes):");
  for (int i = 0; i < 32; i++) {
    if (encodedMessage[i] < 0x10) Serial.print("0");
    Serial.print(encodedMessage[i], HEX);
    Serial.print(" ");
    if ((i + 1) % 16 == 0) Serial.println();
  }
  Serial.println();

  // Look for the NDEF TLV structure starting from the beginning
  int tlvOffset = 0;
  bool foundNdefTlv = false;
  
  // Search for NDEF TLV (0x03) in the first few bytes
  for (int i = 0; i < 16; i++) {
    if (encodedMessage[i] == 0x03) {
      tlvOffset = i;
      foundNdefTlv = true;
      Serial.print("Found NDEF TLV at offset: ");
      Serial.println(tlvOffset);
      break;
    }
  }

  if (!foundNdefTlv) {
    Serial.println("No NDEF TLV found in tag data");
    return false;
  }

  // Get the NDEF message length from TLV
  uint16_t ndefMessageLength = 0;
  int ndefRecordOffset = 0;
  
  if (encodedMessage[tlvOffset + 1] == 0xFF) {
    // Extended length format: next 2 bytes contain the actual length
    ndefMessageLength = (encodedMessage[tlvOffset + 2] << 8) | encodedMessage[tlvOffset + 3];
    ndefRecordOffset = tlvOffset + 4; // Skip TLV tag + 0xFF + 2 length bytes
    Serial.print("NDEF Message Length (extended): ");
  } else {
    // Standard length format: single byte contains the length
    ndefMessageLength = encodedMessage[tlvOffset + 1];
    ndefRecordOffset = tlvOffset + 2; // Skip TLV tag + 1 length byte
    Serial.print("NDEF Message Length (standard): ");
  }
  Serial.println(ndefMessageLength);

  // Get pointer to NDEF record
  const byte* ndefRecord = &encodedMessage[ndefRecordOffset];
  
  // Parse NDEF record header
  byte recordHeader = ndefRecord[0];
  byte typeLength = ndefRecord[1];
  
  Serial.print("NDEF Record Header: 0x");
  Serial.println(recordHeader, HEX);
  Serial.print("Type Length: ");
  Serial.println(typeLength);

  // Determine payload length (can be 1 or 4 bytes depending on SR flag)
  uint32_t payloadLength = 0;
  byte payloadLengthBytes = 1;
  byte payloadLengthOffset = 2;
  
  // Check if Short Record (SR) flag is set (bit 4)
  if (recordHeader & 0x10) { // SR flag
    payloadLength = ndefRecord[2];
    payloadLengthBytes = 1;
    payloadLengthOffset = 2;
  } else {
    // Long record format (4 bytes for payload length)
    payloadLength = (ndefRecord[2] << 24) | (ndefRecord[3] << 16) | 
                   (ndefRecord[4] << 8) | ndefRecord[5];
    payloadLengthBytes = 4;
    payloadLengthOffset = 2;
  }

  Serial.print("Payload Length: ");
  Serial.println(payloadLength);
  Serial.print("Payload Length Bytes: ");
  Serial.println(payloadLengthBytes);

  // Check for ID field (if IL flag is set)
  byte idLength = 0;
  if (recordHeader & 0x08) { // IL flag
    idLength = ndefRecord[payloadLengthOffset + payloadLengthBytes];
    Serial.print("ID Length: ");
    Serial.println(idLength);
  }

  // Calculate offset to payload
  byte payloadOffset = 1 + 1 + payloadLengthBytes + typeLength + idLength;
  
  Serial.print("Calculated payload offset: ");
  Serial.println(payloadOffset);

  // Verify we have enough data
  if (payloadOffset + payloadLength > ndefMessageLength) {
    Serial.println("Invalid NDEF structure - payload extends beyond message");
    Serial.print("Payload offset + length: ");
    Serial.print(payloadOffset + payloadLength);
    Serial.print(", NDEF message length: ");
    Serial.println(ndefMessageLength);
    return false;
  }

  // Print the record type for debugging
  Serial.print("Record Type: ");
  for (int i = 0; i < typeLength; i++) {
    Serial.print((char)ndefRecord[1 + 1 + payloadLengthBytes + i]);
  }
  Serial.println();

  nfcJsonData = "";

  // Extract JSON payload with validation
  uint32_t actualJsonLength = 0;
  for (uint32_t i = 0; i < payloadLength; i++) {
    byte currentByte = ndefRecord[payloadOffset + i];
    
    // Stop at null terminator or if we find the end of JSON
    if (currentByte == 0x00) {
      Serial.print("Found null terminator at position: ");
      Serial.println(i);
      break;
    }
    
    // Only add printable characters and common JSON characters
    if (currentByte >= 32 && currentByte <= 126) {
      nfcJsonData += (char)currentByte;
      actualJsonLength++;
    } else {
      Serial.print("Skipping non-printable byte at position ");
      Serial.print(i);
      Serial.print(": 0x");
      Serial.println(currentByte, HEX);
    }
    
    // Check if we've reached the end of a JSON object
    if (currentByte == '}') {
      // Count opening and closing braces to detect complete JSON
      int braceCount = 0;
      for (uint32_t j = 0; j <= i; j++) {
        if (ndefRecord[payloadOffset + j] == '{') braceCount++;
        else if (ndefRecord[payloadOffset + j] == '}') braceCount--;
      }
      
      if (braceCount == 0) {
        Serial.print("Found complete JSON object at position: ");
        Serial.println(i);
        actualJsonLength = i + 1;
        break;
      }
    }
  }

  Serial.print("Actual JSON length extracted: ");
  Serial.println(actualJsonLength);
  Serial.print("Total nfcJsonData length: ");
  Serial.println(nfcJsonData.length());
  Serial.println("=== DECODED JSON DATA START ===");
  Serial.println(nfcJsonData);
  Serial.println("=== DECODED JSON DATA END ===");
  
  // Check if JSON was truncated
  if (nfcJsonData.length() < payloadLength && !nfcJsonData.endsWith("}")) {
    Serial.println("WARNING: JSON payload appears to be truncated!");
    Serial.print("Expected payload length: ");
    Serial.println(payloadLength);
    Serial.print("Actual extracted length: ");
    Serial.println(nfcJsonData.length());
  }
  
  // Trim any trailing whitespace or invalid characters
  nfcJsonData.trim();

  // JSON-Dokument verarbeiten
  JsonDocument doc;
  DeserializationError error = deserializeJson(doc, nfcJsonData);
  if (error) 
  {
    nfcJsonData = "";
    Serial.println("Fehler beim Verarbeiten des JSON-Dokuments");
    Serial.print("deserializeJson() failed: ");
    Serial.println(error.f_str());
    return false;
  } 
  else 
  {
    // If spoolman is unavailable, there is no point in continuing
    if(spoolmanConnected){
      // Sende die aktualisierten AMS-Daten an alle WebSocket-Clients
      Serial.println("JSON-Dokument erfolgreich verarbeitet");
      Serial.println(doc.as<String>());
      if (doc["sm_id"].is<String>() && doc["sm_id"] != "" && doc["sm_id"] != "0")
      {
        oledShowProgressBar(2, octoEnabled?5:4, "Spool Tag", "Weighing");
        Serial.println("SPOOL-ID gefunden: " + doc["sm_id"].as<String>());
        activeSpoolId = doc["sm_id"].as<String>();
        lastSpoolId = activeSpoolId;
      }
      else if(doc["location"].is<String>() && doc["location"] != "")
      {
        Serial.println("Location Tag found!");
        String location = doc["location"].as<String>();
        if(lastSpoolId != ""){
          updateSpoolLocation(lastSpoolId, location);
        }
        else
        {
          Serial.println("Location update tag scanned without scanning spool before!");
          oledShowProgressBar(1, 1, "Failure", "Scan spool first");
        }
      }
      // Brand Filament not registered to Spoolman
      else if ((!doc["sm_id"].is<String>() || (doc["sm_id"].is<String>() && (doc["sm_id"] == "0" || doc["sm_id"] == "")))
              && doc["b"].is<String>() && doc["an"].is<String>())
      {
        doc["sm_id"] = "0"; // Ensure sm_id is set to 0
        // If no sm_id is present but the brand is Brand Filament then
        // create a new spool, maybe brand too, in Spoolman
        Serial.println("New Brand Filament Tag found!");
        createBrandFilament(doc, uidString);
      }
      else 
      {
        Serial.println("Keine SPOOL-ID gefunden.");
        activeSpoolId = "";
        oledShowProgressBar(1, 1, "Failure", "Unkown tag");
      }
    }else{
      oledShowProgressBar(octoEnabled?5:4, octoEnabled?5:4, "Failure!", "Spoolman unavailable");
    }
  }

  doc.clear();

  return true;
}

bool quickSpoolIdCheck(String uidString) {
    // Fast-path: Read NDEF structure to quickly locate and check JSON payload
    // This dramatically speeds up known spool recognition
    
    // CRITICAL: Do not execute during write operations!
    if (nfcWriteInProgress) {
        Serial.println("FAST-PATH: Skipped during write operation");
        return false;
    }
    
    Serial.println("=== FAST-PATH: Quick sm_id Check ===");
    
    // Read enough pages to cover NDEF header + beginning of payload (pages 4-8 = 20 bytes)
    uint8_t ndefData[20];
    memset(ndefData, 0, 20);
    
    for (uint8_t page = 4; page < 9; page++) {
        if (!nfc.ntag2xx_ReadPage(page, ndefData + (page - 4) * 4)) {
            Serial.print("Failed to read page ");
            Serial.println(page);
            return false; // Fall back to full read
        }
    }
    
    // Parse NDEF structure to find JSON payload start
    Serial.print("Raw NDEF data (first 20 bytes): ");
    for (int i = 0; i < 20; i++) {
        if (ndefData[i] < 0x10) Serial.print("0");
        Serial.print(ndefData[i], HEX);
        Serial.print(" ");
    }
    Serial.println();
    
    // Look for NDEF TLV (0x03) at the beginning
    int tlvOffset = -1;
    for (int i = 0; i < 8; i++) {
        if (ndefData[i] == 0x03) {
            tlvOffset = i;
            Serial.print("Found NDEF TLV at offset: ");
            Serial.println(tlvOffset);
            break;
        }
    }
    
    if (tlvOffset == -1) {
        Serial.println("✗ FAST-PATH: No NDEF TLV found");
        return false;
    }
    
    // Parse NDEF record to find JSON payload
    int ndefRecordStart;
    if (ndefData[tlvOffset + 1] == 0xFF) {
        // Extended length format
        ndefRecordStart = tlvOffset + 4;
    } else {
        // Standard length format
        ndefRecordStart = tlvOffset + 2;
    }
    
    if (ndefRecordStart >= 20) {
        Serial.println("✗ FAST-PATH: NDEF record starts beyond read data");
        return false;
    }
    
    // Parse NDEF record header
    uint8_t recordHeader = ndefData[ndefRecordStart];
    uint8_t typeLength = ndefData[ndefRecordStart + 1];
    
    // Calculate payload offset
    uint8_t payloadLengthBytes = (recordHeader & 0x10) ? 1 : 4; // SR flag check
    uint8_t idLength = (recordHeader & 0x08) ? ndefData[ndefRecordStart + 2 + payloadLengthBytes + typeLength] : 0; // IL flag check
    
    int payloadOffset = ndefRecordStart + 1 + 1 + payloadLengthBytes + typeLength + idLength;
    
    Serial.print("NDEF Record Header: 0x");
    Serial.print(recordHeader, HEX);
    Serial.print(", Type Length: ");
    Serial.print(typeLength);
    Serial.print(", Payload offset: ");
    Serial.println(payloadOffset);
    
    // Check if payload starts within our read data
    if (payloadOffset >= 20) {
        Serial.println("✗ FAST-PATH: JSON payload starts beyond quick read data - need more pages");
        
        // Read additional pages to get to JSON payload
        uint8_t extraData[16]; // Read 4 more pages
        memset(extraData, 0, 16);
        
        for (uint8_t page = 9; page < 13; page++) {
            if (!nfc.ntag2xx_ReadPage(page, extraData + (page - 9) * 4)) {
                Serial.print("Failed to read additional page ");
                Serial.println(page);
                return false;
            }
        }
        
        // Combine data
        uint8_t combinedData[36];
        memcpy(combinedData, ndefData, 20);
        memcpy(combinedData + 20, extraData, 16);
        
        // Extract JSON from combined data
        String jsonStart = "";
        int jsonStartPos = payloadOffset;
        for (int i = 0; i < 36 - payloadOffset && i < 30; i++) {
            uint8_t currentByte = combinedData[payloadOffset + i];
            if (currentByte >= 32 && currentByte <= 126) {
                jsonStart += (char)currentByte;
            }
            // Stop at first brace to get just the beginning
            if (currentByte == '{' && i > 0) break;
        }
        
        Serial.print("JSON start from extended read: ");
        Serial.println(jsonStart);
        
        // Check for sm_id pattern - look for non-zero sm_id values
        if (jsonStart.indexOf("\"sm_id\":\"") >= 0) {
            int smIdStart = jsonStart.indexOf("\"sm_id\":\"") + 9;
            int smIdEnd = jsonStart.indexOf("\"", smIdStart);
            
            if (smIdEnd > smIdStart && smIdEnd < jsonStart.length()) {
                String quickSpoolId = jsonStart.substring(smIdStart, smIdEnd);
                Serial.print("Found sm_id in extended read: ");
                Serial.println(quickSpoolId);
                
                // Only process if sm_id is not "0" (known spool)
                if (quickSpoolId != "0" && quickSpoolId.length() > 0) {
                    Serial.println("✓ FAST-PATH: Known spool detected!");
                    
                    // Set as active spool immediately
                    activeSpoolId = quickSpoolId;
                    lastSpoolId = activeSpoolId;
                    
                    oledShowProgressBar(2, octoEnabled?5:4, "Known Spool", "Quick mode");
                    Serial.println("✓ FAST-PATH SUCCESS: Known spool processed quickly");
                    return true;
                } else {
                    Serial.println("✗ FAST-PATH: sm_id is 0 - new brand filament, need full read");
                    return false;
                }
            }
        }
        
        Serial.println("✗ FAST-PATH: No sm_id pattern in extended read");
        return false;
    }
    
    // Extract JSON payload from the available data
    String quickJson = "";
    for (int i = payloadOffset; i < 20 && i < payloadOffset + 15; i++) {
        uint8_t currentByte = ndefData[i];
        if (currentByte >= 32 && currentByte <= 126) {
            quickJson += (char)currentByte;
        }
    }
    
    Serial.print("Quick JSON data: ");
    Serial.println(quickJson);
    
    // Look for sm_id pattern in the beginning of JSON - check for known vs new spools
    if (quickJson.indexOf("\"sm_id\":\"") >= 0) {
        Serial.println("✓ FAST-PATH: sm_id field found");
        
        // Extract sm_id from quick data
        int smIdStart = quickJson.indexOf("\"sm_id\":\"") + 9;
        int smIdEnd = quickJson.indexOf("\"", smIdStart);
        
        if (smIdEnd > smIdStart && smIdEnd < quickJson.length()) {
            String quickSpoolId = quickJson.substring(smIdStart, smIdEnd);
            Serial.print("✓ Quick extracted sm_id: ");
            Serial.println(quickSpoolId);
            
            // Only process known spools (sm_id != "0") via fast path
            if (quickSpoolId != "0" && quickSpoolId.length() > 0) {
                Serial.println("✓ FAST-PATH: Known spool detected!");
                
                // Set as active spool immediately
                activeSpoolId = quickSpoolId;
                lastSpoolId = activeSpoolId;
                
                oledShowProgressBar(2, octoEnabled?5:4, "Known Spool", "Quick mode");
                Serial.println("✓ FAST-PATH SUCCESS: Known spool processed quickly");
                return true;
            } else {
                Serial.println("✗ FAST-PATH: sm_id is 0 - new brand filament, need full read");
                return false; // sm_id="0" means new brand filament, needs full processing
            }
        } else {
            Serial.println("✗ FAST-PATH: Could not extract complete sm_id value");
            return false; // Need full read to get complete sm_id
        }
    }
    
    // Check for other patterns that require full read
    if (quickJson.indexOf("\"location\":\"") >= 0) {
        Serial.println("✓ FAST-PATH: Location tag detected");
        return false; // Need full read for location processing
    }
    
    if (quickJson.indexOf("\"brand\":\"") >= 0) {
        Serial.println("✓ FAST-PATH: Brand filament detected - may need full processing");
        return false; // Need full read for brand filament creation
    }
    
    Serial.println("✗ FAST-PATH: No recognizable pattern - falling back to full read");
    return false; // Fall back to full tag reading
}

void writeJsonToTag(void *parameter) {
  NfcWriteParameterType* params = (NfcWriteParameterType*)parameter;

  // Gib die erstellte NDEF-Message aus
  Serial.println("Erstelle NDEF-Message...");
  Serial.println(params->payload);

  nfcReaderState = NFC_WRITING;
  nfcWriteInProgress = true; // Block high-level tag operations during write

  // Do NOT suspend the reading task - we need NFC interface for verification
  // Just use nfcWriteInProgress to prevent scanning and fast-path operations
  Serial.println("NFC Write Task starting - High-level operations blocked, low-level NFC available");

  //pauseBambuMqttTask = true;
  // aktualisieren der Website wenn sich der Status ändert
  sendNfcData();
  vTaskDelay(100 / portTICK_PERIOD_MS);
  // Wait 10sec for tag
  uint8_t success = 0;
  String uidString = "";
  for (uint16_t i = 0; i < 20; i++) {
    uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
    uint8_t uidLength;
    // yield before potentially waiting for 400ms
    yield();
    esp_task_wdt_reset();
    success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 400);
    if (success) {
      for (uint8_t i = 0; i < uidLength; i++) {
        //TBD: Rework to remove all the string operations
        uidString += String(uid[i], HEX);
        if (i < uidLength - 1) {
            uidString += ":"; // Optional: Trennzeichen hinzufügen
        }
      }
      foundNfcTag(nullptr, success);
      break;
    }

    yield();
    esp_task_wdt_reset();
    vTaskDelay(pdMS_TO_TICKS(1));
  }

  if (success)
  {
    oledShowProgressBar(1, 3, "Write Tag", "Writing");

    // Schreibe die NDEF-Message auf den Tag
    success = ntag2xx_WriteNDEF(params->payload);
    if (success) 
    {
        Serial.println("NDEF-Message erfolgreich auf den Tag geschrieben");
        //oledShowMessage("NFC-Tag written");
        //vTaskDelay(1000 / portTICK_PERIOD_MS);
        nfcReaderState = NFC_WRITE_SUCCESS;
        // aktualisieren der Website wenn sich der Status ändert
        sendNfcData();
        pauseBambuMqttTask = false;
        
        if(params->tagType){
          // TBD: should this be simplified?
          if (updateSpoolTagId(uidString, params->payload) && params->tagType) {
            
          }else{
            // Potentially handle errors
          }
        }else{
          oledShowProgressBar(1, 1, "Write Tag", "Done!");
        }
        
        // CRITICAL: Properly stabilize NFC interface after write operation
        Serial.println();
        Serial.println("=== POST-WRITE NFC STABILIZATION ===");
        
        // Wait for tag operations to complete
        vTaskDelay(500 / portTICK_PERIOD_MS);
        
        // Test tag presence and remove detection
        uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
        uint8_t uidLength;
        int tagRemovalChecks = 0;
        
        Serial.println("Warte bis Tag entfernt wird...");
        
        // Monitor tag presence
        while (tagRemovalChecks < 10) {
          yield();
          esp_task_wdt_reset();
          
          bool tagPresent = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500);
          
          if (!tagPresent) {
            Serial.println("✓ Tag wurde entfernt - NFC bereit für nächsten Scan");
            break;
          }
          
          tagRemovalChecks++;
          Serial.print("Tag noch vorhanden (");
          Serial.print(tagRemovalChecks);
          Serial.println("/10)");
          
          vTaskDelay(500 / portTICK_PERIOD_MS);
        }
        
        if (tagRemovalChecks >= 10) {
          Serial.println("WARNUNG: Tag wurde nicht entfernt - fahre trotzdem fort");
        }
        
        // Additional interface stabilization before resuming normal operations
        Serial.println("Stabilisiere NFC-Interface für normale Operationen...");
        vTaskDelay(200 / portTICK_PERIOD_MS);
        
        // Test if interface is ready for normal scanning
        uint8_t interfaceTestBuffer[4];
        bool interfaceReady = false;
        
        for (int testAttempt = 0; testAttempt < 3; testAttempt++) {
          // Try a simple interface operation (without requiring tag presence)
          Serial.print("Interface readiness test ");
          Serial.print(testAttempt + 1);
          Serial.print("/3... ");
          
          // Use a safe read operation that doesn't depend on tag presence
          // This tests if the PN532 chip itself is responsive
          uint32_t versiondata = nfc.getFirmwareVersion();
          if (versiondata != 0) {
            Serial.println("✓");
            interfaceReady = true;
            break;
          } else {
            Serial.println("❌");
            vTaskDelay(100 / portTICK_PERIOD_MS);
          }
        }
        
        if (!interfaceReady) {
          Serial.println("WARNUNG: NFC-Interface reagiert nicht - könnte normale Scans beeinträchtigen");
        } else {
          Serial.println("✓ NFC-Interface ist bereit für normale Scans");
        }
        
        Serial.println("=========================================");
        
        vTaskResume(RfidReaderTask);
        vTaskDelay(500 / portTICK_PERIOD_MS);        
    } 
    else 
    {
        Serial.println("Fehler beim Schreiben der NDEF-Message auf den Tag");
        oledShowIcon("failed");
        vTaskDelay(2000 / portTICK_PERIOD_MS);
        nfcReaderState = NFC_WRITE_ERROR;
    }
  }
  else
  {
    Serial.println("Fehler: Kein Tag zu schreiben gefunden.");
    oledShowProgressBar(1, 1, "Failure!", "No tag found");
    vTaskDelay(2000 / portTICK_PERIOD_MS);
    nfcReaderState = NFC_IDLE;
  }
  
  sendWriteResult(nullptr, success);
  sendNfcData();

  // Only reset the write protection flag - reading task was never suspended
  nfcWriteInProgress = false; // Re-enable high-level tag operations
  pauseBambuMqttTask = false;

  free(params->payload);
  delete params;

  vTaskDelete(NULL);
}

void startWriteJsonToTag(const bool isSpoolTag, const char* payload) {
  NfcWriteParameterType* parameters = new NfcWriteParameterType();
  parameters->tagType = isSpoolTag;
  parameters->payload = strdup(payload);
  
  // Task nicht mehrfach starten
  if (nfcReaderState == NFC_IDLE || nfcReaderState == NFC_READ_ERROR || nfcReaderState == NFC_READ_SUCCESS) {
    oledShowProgressBar(0, 1, "Write Tag", "Place tag now");
    // Erstelle die Task
    xTaskCreate(
        writeJsonToTag,        // Task-Funktion
        "WriteJsonToTagTask",       // Task-Name
        5115,                        // Stackgröße in Bytes
        (void*)parameters,         // Parameter
        rfidWriteTaskPrio,           // Priorität
        NULL                         // Task-Handle (nicht benötigt)
    );
  }else{
    oledShowProgressBar(0, 1, "FAILURE", "NFC busy!");
    // TBD: Add proper error handling (website)
  }
}

void scanRfidTask(void * parameter) {
  Serial.println("RFID Task gestartet");
  for(;;) {
    // Skip scanning during write operations, but keep NFC interface active
    if (nfcReaderState != NFC_WRITING && !nfcWriteInProgress && !nfcReadingTaskSuspendRequest && !booting)
    {
      nfcReadingTaskSuspendState = false;
      yield();

      uint8_t success;
      uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
      uint8_t uidLength;

      success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500);

      foundNfcTag(nullptr, success);
      
      // As long as there is still a tag on the reader, do not try to read it again
      if (success && nfcReaderState == NFC_IDLE)
      {
        // Set the current tag as not processed
        tagProcessed = false;

        // Display some basic information about the card
        Serial.println("Found an ISO14443A card");

        nfcReaderState = NFC_READING;

        oledShowProgressBar(0, octoEnabled?5:4, "Reading", "Detecting tag");

        // Wait 1 second after tag detection to stabilize connection
        Serial.println("Tag detected, waiting 1 second for stabilization...");
        vTaskDelay(1000 / portTICK_PERIOD_MS);

        // create Tag UID string
        String uidString = "";
        for (uint8_t i = 0; i < uidLength; i++) {
          //TBD: Rework to remove all the string operations
          uidString += String(uid[i], HEX);
          if (i < uidLength - 1) {
              uidString += ":"; // Optional: Trennzeichen hinzufügen
          }
        }
        
        if (uidLength == 7)
        {
          // Try fast-path detection first for known spools
          if (quickSpoolIdCheck(uidString)) {
              Serial.println("✓ FAST-PATH: Tag processed quickly, skipping full read");
              pauseBambuMqttTask = false;
              // Set reader back to idle for next scan
              nfcReaderState = NFC_READ_SUCCESS;
              delay(500); // Small delay before next scan
              continue; // Skip full tag reading and continue scan loop
          }

          Serial.println("Continuing with full tag read after fast-path check");

          uint16_t tagSize = readTagSize();
          if(tagSize > 0)
          {
            // Create a buffer depending on the size of the tag
            uint8_t* data = (uint8_t*)malloc(tagSize);
            memset(data, 0, tagSize);

            // We probably have an NTAG2xx card (though it could be Ultralight as well)
            Serial.println("Seems to be an NTAG2xx tag (7 byte UID)");
            Serial.print("Tag size: ");
            Serial.print(tagSize);
            Serial.println(" bytes");
            
            uint8_t numPages = readTagSize()/4;
            
            for (uint8_t i = 4; i < 4+numPages; i++) {
              
              if (!nfc.ntag2xx_ReadPage(i, data+(i-4) * 4))
              {
                break; // Stop if reading fails
              }
             
              // Check for NDEF message end
              if (data[(i - 4) * 4] == 0xFE) 
              {
                Serial.println("Found NDEF message end marker");
                break; // End of NDEF message
              }

              yield();
              esp_task_wdt_reset();
              // Increased delay to ensure stable reading
              vTaskDelay(pdMS_TO_TICKS(5)); // Increased from 1ms to 5ms
            }
            
            Serial.println("Tag reading completed, starting NDEF decode...");
            
            if (!decodeNdefAndReturnJson(data, uidString)) 
            {
              oledShowProgressBar(1, 1, "Failure", "Unknown tag");
              nfcReaderState = NFC_READ_ERROR;
            }
            else 
            {
              nfcReaderState = NFC_READ_SUCCESS;
            }

            free(data);
          }
          else
          {
            oledShowProgressBar(1, 1, "Failure", "Tag read error");
            nfcReaderState = NFC_READ_ERROR;
          }
        }
        else
        {
          //TBD: Show error here?!
          oledShowProgressBar(1, 1, "Failure", "Unkown tag type");
          Serial.println("This doesn't seem to be an NTAG2xx tag (UUID length != 7 bytes)!");
        }
      }

      if (!success && nfcReaderState != NFC_IDLE && !nfcReadingTaskSuspendRequest)
      {
        nfcReaderState = NFC_IDLE;
        //uidString = "";
        nfcJsonData = "";
        activeSpoolId = "";
        Serial.println("Tag entfernt");
        if (!bambuCredentials.autosend_enable) oledShowWeight(weight);
      }
      // Reset state after successful read when tag is removed
      else if (!success && nfcReaderState == NFC_READ_SUCCESS)
      {
        nfcReaderState = NFC_IDLE;
        Serial.println("Tag nach erfolgreichem Lesen entfernt - bereit für nächsten Tag");
      }

      // Add a longer pause after successful reading to prevent immediate re-reading
      if (nfcReaderState == NFC_READ_SUCCESS) {
        Serial.println("Tag erfolgreich gelesen - warte 5 Sekunden vor nächstem Scan");
        vTaskDelay(5000 / portTICK_PERIOD_MS); // 5 second pause
      }

      // aktualisieren der Website wenn sich der Status ändert
      sendNfcData();
    }
    else
    {
      nfcReadingTaskSuspendState = true;
      
      // Different behavior for write protection vs. full suspension
      if (nfcWriteInProgress) {
        // During write: Just pause scanning, don't disable NFC interface
        // Serial.println("NFC Scanning paused during write operation");
        vTaskDelay(100 / portTICK_PERIOD_MS); // Shorter delay during write
      } else {
        // Full suspension requested
        Serial.println("NFC Reading disabled");
        vTaskDelay(1000 / portTICK_PERIOD_MS);
      }
    }
    yield();
  }
}

void startNfc() {
  oledShowProgressBar(5, 7, DISPLAY_BOOT_TEXT, "NFC init");
  nfc.begin();                                           // Beginne Kommunikation mit RFID Leser
  delay(1000);
  unsigned long versiondata = nfc.getFirmwareVersion();  // Lese Versionsnummer der Firmware aus
  if (! versiondata) {                                   // Wenn keine Antwort kommt
    Serial.println("Kann kein RFID Board finden !");            // Sende Text "Kann kein..." an seriellen Monitor
    oledShowMessage("No RFID Board found");
    vTaskDelay(2000 / portTICK_PERIOD_MS);
  }
  else {
    Serial.print("Chip PN5 gefunden"); Serial.println((versiondata >> 24) & 0xFF, HEX); // Sende Text und Versionsinfos an seriellen
    Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);      // Monitor, wenn Antwort vom Board kommt
    Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);                  // 

    nfc.SAMConfig();
    // Set the max number of retry attempts to read from a card
    // This prevents us from waiting forever for a card, which is
    // the default behaviour of the PN532.
    //nfc.setPassiveActivationRetries(0x7F);
    //nfc.setPassiveActivationRetries(0xFF);

    BaseType_t result = xTaskCreatePinnedToCore(
      scanRfidTask, /* Function to implement the task */
      "RfidReader", /* Name of the task */
      5115,  /* Stack size in words */
      NULL,  /* Task input parameter */
      rfidTaskPrio,  /* Priority of the task */
      &RfidReaderTask,  /* Task handle. */
      rfidTaskCore); /* Core where the task should run */

      if (result != pdPASS) {
        Serial.println("Fehler beim Erstellen des RFID Tasks");
    } else {
        Serial.println("RFID Task erfolgreich erstellt");
    }
  }
}