// Hilfsfunktion zur Generierung der nicht-blockierenden C++ Logik für jedes Display
const generateBitDisplayHelper = (name, maxVal, errA, errB, applyCode) => `
long bd_${name}_val = 0;

void apply_bd_${name}(uint8_t val) {
${applyCode}
}

void update_bd_${name}() {
  static long last_val = -999;
  static unsigned long timer = 0;
  static bool errToggle = false;
  static bool forceUpdate = true;
  
  long v = bd_${name}_val;
  bool isErr = (v < 0 || v > ${maxVal});
  
  if(v != last_val) {
    last_val = v;
    forceUpdate = true;
    if(isErr) { timer = millis(); errToggle = false; }
  }
  
  if(isErr) {
    if(millis() - timer >= 1000 || forceUpdate) {
      if(!forceUpdate) {
        timer = millis();
        errToggle = !errToggle;
      }
      forceUpdate = false;
      uint8_t outVal = errToggle ? ${errA} : ${errB}; 
      apply_bd_${name}(outVal);
    }
  } else {
    if(forceUpdate) {
      forceUpdate = false;
      apply_bd_${name}(v);
    }
  }
}
`;

Blockly.defineBlocksWithJsonArray([
    // ==========================================
    // 1. SETUP: DISKRETE PINS
    // ==========================================
    {
      "type": "bit_display_setup_pins",
      "message0": "🛠️ Bit-Anzeige (Pins) Setup | Name: %1",
      "args0": [ {"type": "field_input", "name": "NAME", "text": "Anzeige1"} ],
      "message1": "Modus: %1",
      "args1": [
        {"type": "field_dropdown", "name": "BITS", "options": [["8-Bit (0-255)", "8"], ["4-Bit (0-15)", "4"]]}
      ],
      "message2": "Pins [Bit 0 bis 3]: %1, %2, %3, %4",
      "args2": [
        {"type": "field_input", "name": "P0", "text": "2"},
        {"type": "field_input", "name": "P1", "text": "3"},
        {"type": "field_input", "name": "P2", "text": "4"},
        {"type": "field_input", "name": "P3", "text": "5"}
      ],
      "message3": "Pins [Bit 4 bis 7] (nur bei 8-Bit): %1, %2, %3, %4",
      "args3": [
        {"type": "field_input", "name": "P4", "text": "6"},
        {"type": "field_input", "name": "P5", "text": "7"},
        {"type": "field_input", "name": "P6", "text": "8"},
        {"type": "field_input", "name": "P7", "text": "9"}
      ],
      "previousStatement": null,
      "nextStatement": null,
      "colour": 160,
      "tooltip": "Hier richtest du deine Bit-Anzeige mit einzelnen LEDs ein. Vergiss nicht, Vorwiderstände zu nutzen!"
    },

    // ==========================================
    // 2. SETUP: NEOPIXEL
    // ==========================================
    {
      "type": "bit_display_setup_neopixel",
      "message0": "🛠️ Bit-Anzeige (NeoPixel) Setup | Name: %1",
      "args0": [ {"type": "field_input", "name": "NAME", "text": "Anzeige1"} ],
      "message1": "Modus: %1 | LSB (Bit 0): %2",
      "args1": [
        {"type": "field_dropdown", "name": "BITS", "options": [["8-Bit (0-255)", "8"], ["4-Bit (0-15)", "4"]]},
        {"type": "field_dropdown", "name": "DIR", "options": [["Rechts (Standard)", "RIGHT"], ["Links", "LEFT"]]}
      ],
      "message2": "Start-LED Index (ganz links): %1",
      "args2": [ {"type": "field_number", "name": "START", "value": 0, "min": 0} ],
      "message3": "Farbe AN 🔴 %1 🟢 %2 🔵 %3",
      "args3": [
        {"type": "field_number", "name": "R1", "value": 0, "min":0, "max":255},
        {"type": "field_number", "name": "G1", "value": 255, "min":0, "max":255},
        {"type": "field_number", "name": "B1", "value": 0, "min":0, "max":255}
      ],
      "message4": "Farbe AUS 🔴 %1 🟢 %2 🔵 %3",
      "args4": [
        {"type": "field_number", "name": "R0", "value": 10, "min":0, "max":255},
        {"type": "field_number", "name": "G0", "value": 0, "min":0, "max":255},
        {"type": "field_number", "name": "B0", "value": 0, "min":0, "max":255}
      ],
      "previousStatement": null,
      "nextStatement": null,
      "colour": 140,
      "tooltip": "Hier richtest du deine Bit-Anzeige auf einem NeoPixel-Streifen ein. Erfordert zusätzlich den normalen NeoPixel-Setup-Block!"
    },

    // ==========================================
    // 3. SETUP: MAX7219 MATRIX
    // ==========================================
    {
      "type": "bit_display_setup_max",
      "message0": "🛠️ Bit-Anzeige (MAX7219) Setup | Name: %1",
      "args0": [ {"type": "field_input", "name": "NAME", "text": "Anzeige1"} ],
      "message1": "Modus: %1 | LSB (Bit 0): %2",
      "args1": [
        {"type": "field_dropdown", "name": "BITS", "options": [["8-Bit (0-255)", "8"], ["4-Bit (0-15)", "4"]]},
        {"type": "field_dropdown", "name": "DIR", "options": [["Rechts (Standard)", "RIGHT"], ["Links", "LEFT"]]}
      ],
      "message2": "Zeile (Y-Achse, 0-7): %1",
      "args2": [ {"type": "field_number", "name": "ROW", "value": 0, "min": 0, "max": 7} ],
      "message3": "Start-Spalte (X-Achse, ganz links): %1",
      "args3": [ {"type": "field_number", "name": "COL", "value": 0, "min": 0} ],
      "previousStatement": null,
      "nextStatement": null,
      "colour": 140,
      "tooltip": "Hier richtest du deine Bit-Anzeige auf der Dot-Matrix ein. Erfordert zusätzlich den normalen MAX7219-Setup-Block!"
    },

    // ==========================================
    // 4. ACTION: SCHREIBEN
    // ==========================================
    {
      "type": "bit_display_write",
      "message0": "Schreibe auf Bit-Anzeige %1",
      "args0": [ {"type": "field_input", "name": "NAME", "text": "Anzeige1"} ],
      "message1": "Zahl: %1",
      "args1": [ {"type": "input_value", "name": "VAL", "check": "Number"} ],
      "previousStatement": null,
      "nextStatement": null,
      "colour": 160,
      "tooltip": "Schreibt eine Zahl auf deine Anzeige. Bei falschen Werten (z. B. > 255) startet automatisch das Warnblinken!"
    }
]);

// =======================================================================
// DEZENTRALE SCANNER (Hardware Setup & Hintergrundlogik)
// =======================================================================

ArduinoGenerator.hardwareScanners['bit_display_setup_pins'] = function(block) {
    const name = block.getFieldValue('NAME').trim();
    const bits = block.getFieldValue('BITS');
    const numBits = parseInt(bits);
    
    let applyCode = "";
    for(let i=0; i<numBits; i++) {
        let pin = block.getFieldValue('P' + i).trim();
        ArduinoGenerator.usedPinsOutput.add(pin);
        applyCode += `  digitalWrite(pin${pin}, (val & (1 << ${i})) ? HIGH : LOW);\n`;
    }
    
    const maxVal = bits === '8' ? 255 : 15;
    const errA = bits === '8' ? 170 : 10;
    const errB = bits === '8' ? 85 : 5;
    
    ArduinoGenerator.globals_.add(generateBitDisplayHelper(name, maxVal, errA, errB, applyCode));
    ArduinoGenerator.autoLoop_.push(`  update_bd_${name}();\n`);
};

ArduinoGenerator.hardwareScanners['bit_display_setup_neopixel'] = function(block) {
    const name = block.getFieldValue('NAME').trim();
    const bits = block.getFieldValue('BITS');
    const dir = block.getFieldValue('DIR');
    const numBits = parseInt(bits);
    const start = block.getFieldValue('START');
    
    const r1 = block.getFieldValue('R1');
    const g1 = block.getFieldValue('G1');
    const b1 = block.getFieldValue('B1');
    const r0 = block.getFieldValue('R0');
    const g0 = block.getFieldValue('G0');
    const b0 = block.getFieldValue('B0');
    
    let applyCode = `  for(int i=0; i<${numBits}; i++) {\n`;
    if (dir === 'RIGHT') {
        applyCode += `    int pIdx = ${start} + (${numBits - 1} - i);\n`;
    } else {
        applyCode += `    int pIdx = ${start} + i;\n`;
    }
    applyCode += `    bool b = (val & (1 << i));\n`;
    applyCode += `    leds[pIdx] = b ? CRGB(${r1},${g1},${b1}) : CRGB(${r0},${g0},${b0});\n`;
    applyCode += `  }\n`;
    applyCode += `  FastLED.show();\n`;
    
    const maxVal = bits === '8' ? 255 : 15;
    const errA = bits === '8' ? 170 : 10;
    const errB = bits === '8' ? 85 : 5;
    
    ArduinoGenerator.globals_.add(generateBitDisplayHelper(name, maxVal, errA, errB, applyCode));
    ArduinoGenerator.autoLoop_.push(`  update_bd_${name}();\n`);
};

ArduinoGenerator.hardwareScanners['bit_display_setup_max'] = function(block) {
    const name = block.getFieldValue('NAME').trim();
    const bits = block.getFieldValue('BITS');
    const dir = block.getFieldValue('DIR');
    const numBits = parseInt(bits);
    const row = block.getFieldValue('ROW');
    const col = block.getFieldValue('COL');
    
    let applyCode = `  for(int i=0; i<${numBits}; i++) {\n`;
    if (dir === 'RIGHT') {
        applyCode += `    int cIdx = ${col} + (${numBits - 1} - i);\n`;
    } else {
        applyCode += `    int cIdx = ${col} + i;\n`;
    }
    applyCode += `    bool b = (val & (1 << i));\n`;
    applyCode += `    P.getGraphicObject()->setPoint(${row}, cIdx, b);\n`;
    applyCode += `  }\n`;
    
    const maxVal = bits === '8' ? 255 : 15;
    const errA = bits === '8' ? 170 : 10;
    const errB = bits === '8' ? 85 : 5;
    
    ArduinoGenerator.globals_.add(generateBitDisplayHelper(name, maxVal, errA, errB, applyCode));
    ArduinoGenerator.autoLoop_.push(`  update_bd_${name}();\n`);
};

// =======================================================================
// CODE GENERATOREN
// =======================================================================

// Die Setup-Blöcke erzeugen keinen Inline-Code (alles passiert per Scanner in den Globals/AutoLoop)
ArduinoGenerator.forBlock['bit_display_setup_pins'] = function() { return ''; };
ArduinoGenerator.forBlock['bit_display_setup_neopixel'] = function() { return ''; };
ArduinoGenerator.forBlock['bit_display_setup_max'] = function() { return ''; };

// Der Aktionsblock schreibt einfach die Variable im Loop
ArduinoGenerator.forBlock['bit_display_write'] = function(block) {
    const name = block.getFieldValue('NAME').trim();
    const val = ArduinoGenerator.valueToCode(block, 'VAL', 0) || '0';
    return `  bd_${name}_val = ${val};\n`;
};