
// ==========================================
// 1. BLOCKLY BLOCK-DEFINITIONEN (JSON)
// ==========================================
Blockly.defineBlocksWithJsonArray([
    // --- 1. SETUP BLOCK ---
    {
        "type": "can_setup",
        "message0": "CAN-Bus Setup | Meine Modul-ID: %1",
        "args0": [
            {
                "type": "field_dropdown",
                "name": "MOD_ID",
                "options": [
                    ["Modul 1 (Schaltzentrale)", "1"],
                    ["Modul 2", "2"], ["Modul 3", "3"], ["Modul 4", "4"],
                    ["Modul 5", "5"], ["Modul 6", "6"], ["Modul 7", "7"],
                    ["Modul 8", "8"], ["Modul 9", "9"], ["Modul 10", "10"],
                    ["Modul 11", "11"]
                ]
            }
        ],
        "previousStatement": null,
        "nextStatement": null,
        "colour": 200,
        "tooltip": "Initialisiert den CAN-Bus am Arduino UNO R4. (Pins: CRX / CTX)"
    },
    
    // --- 2. SENDEN: ZYKLISCH ---
    {
        "type": "can_send_cyclic",
        "message0": "CAN Senden (Zyklisch) | Kanal %1 | Typ %2 | Wert %3 | Alle %4 ms",
        "args0": [
            { "type": "field_number", "name": "CHANNEL", "value": 0, "min": 0, "max": 127 },
            {
                "type": "field_dropdown",
                "name": "TYPE",
                "options": [
                    ["Bit / Schalter (1 Byte)", "0"],
                    ["Ganze Zahl / Int (4 Byte)", "1"],
                    ["Ganze Zahl x10 / 1 Kommastelle (2 Byte)", "2"],
                    ["Kommazahl / Float (4 Byte)", "3"]
                ]
            },
            { "type": "input_value", "name": "VAL" },
            { "type": "field_number", "name": "INTERVAL", "value": 1000, "min": 10 }
        ],
        "previousStatement": null,
        "nextStatement": null,
        "colour": 200,
        "tooltip": "Sendet einen Wert automatisch im festgelegten Takt auf den Bus."
    },

    // --- 3. SENDEN: BEI ÄNDERUNG ---
    {
        "type": "can_send_change",
        "message0": "CAN Senden (Bei Änderung) | Kanal %1 | Typ %2 | Wert %3",
        "args0": [
            { "type": "field_number", "name": "CHANNEL", "value": 0, "min": 0, "max": 127 },
            {
                "type": "field_dropdown",
                "name": "TYPE",
                "options": [
                    ["Bit / Schalter (1 Byte)", "0"],
                    ["Ganze Zahl / Int (4 Byte)", "1"],
                    ["Ganze Zahl x10 / 1 Kommastelle (2 Byte)", "2"],
                    ["Kommazahl / Float (4 Byte)", "3"]
                ]
            },
            { "type": "input_value", "name": "VAL" }
        ],
        "previousStatement": null,
        "nextStatement": null,
        "colour": 200,
        "tooltip": "Sendet den Wert nur, wenn er sich seit dem letzten Durchlauf verändert hat (Flankenauswertung)."
    },

    // --- 4. EMPFANGEN: EVENT-BLOCK ---
    {
        "type": "can_on_receive",
        "message0": "Wenn CAN empfangen | Von Modul %1 | Kanal %2 | Typ %3 %4 Speichere in: %5 %6 Dann mache: %7",
        "args0": [
            {
                "type": "field_dropdown",
                "name": "MOD_ID",
                "options": [
                    ["Modul 1", "1"], ["Modul 2", "2"], ["Modul 3", "3"],
                    ["Modul 4", "4"], ["Modul 5", "5"], ["Modul 6", "6"],
                    ["Modul 7", "7"], ["Modul 8", "8"], ["Modul 9", "9"],
                    ["Modul 10", "10"], ["Modul 11", "11"]
                ]
            },
            { "type": "field_number", "name": "CHANNEL", "value": 0, "min": 0, "max": 127 },
            {
                "type": "field_dropdown",
                "name": "TYPE",
                "options": [
                    ["Bit / Schalter", "0"],
                    ["Ganze Zahl / Int", "1"],
                    ["Ganze Zahl x10", "2"],
                    ["Kommazahl / Float", "3"]
                ]
            },
            { "type": "input_dummy" },
            { "type": "field_variable", "name": "VAR", "variable": "can_wert" },
            { "type": "input_dummy" },
            { "type": "input_statement", "name": "DO" }
        ],
        "previousStatement": null,
        "nextStatement": null,
        "colour": 200,
        "tooltip": "Führt den Inhalt aus, sobald die Nachricht eintrifft und übergibt den Wert an die gewählte Variable."
    }
]);

// ==========================================
// 2. HARDWARE SCANNERS (Vorab-Analyse)
// ==========================================

ArduinoGenerator.hardwareScanners['can_setup'] = function(block) {
    if (!ArduinoGenerator.can_rx_handlers) {
        ArduinoGenerator.can_rx_handlers = new Map();
    }
};

ArduinoGenerator.hardwareScanners['can_on_receive'] = function(block) {
    if (!ArduinoGenerator.can_rx_handlers) {
        ArduinoGenerator.can_rx_handlers = new Map();
    }
    const mod = block.getFieldValue('MOD_ID');
    const ch = block.getFieldValue('CHANNEL');
    const type = block.getFieldValue('TYPE');
    const uniqueId = `${mod}_${ch}`;
    
    // Globale Variablen für den C++ Hintergrund-Empfang
    ArduinoGenerator.globals_.add(`float lk_can_val_${uniqueId} = 0.0;`);
    ArduinoGenerator.globals_.add(`bool lk_can_flag_${uniqueId} = false;`);
    
    // Daten in die Map eintragen, damit der Setup-Block später den C++ Poller bauen kann
    ArduinoGenerator.can_rx_handlers.set(uniqueId, { mod: mod, ch: ch, type: type });
};


// ==========================================
// 3. C++ CODE-GENERATOREN
// ==========================================

ArduinoGenerator.forBlock['can_setup'] = function(block) {
    const modId = block.getFieldValue('MOD_ID');
    
    ArduinoGenerator.globals_.add(`#include <Arduino_CAN.h>`);
    ArduinoGenerator.globals_.add(`const int lk_my_can_module_id = ${modId};`);
    
    // Zentrales C++ Unterprogramm zum Senden (Spart enorm Flash-Speicher)
    ArduinoGenerator.globals_.add(`
void lk_can_send(const int mod_id, const int channel, const int type, float value) {
  const int can_id = (mod_id * 128) + channel;
  CanMsg msg;
  msg.id = can_id;
  msg.is_standard_id = true;
  msg.is_data_frame = true;
  
  if (type == 0) { // Bit / Schalter
    msg.data_length = 1;
    msg.data[0] = (value != 0.0f) ? 1 : 0;
  } else if (type == 1) { // Int32
    msg.data_length = 4;
    int32_t val = (int32_t)value;
    memcpy(msg.data, &val, 4);
  } else if (type == 2) { // Int16 x10 (Datensparend)
    msg.data_length = 2;
    int16_t val = (int16_t)(value * 10.0f);
    memcpy(msg.data, &val, 2);
  } else if (type == 3) { // Float
    msg.data_length = 4;
    float val = value;
    memcpy(msg.data, &val, 4);
  }
  CAN.write(msg);
}`);

    // Dynamischer Empfangs-Poller bauen (nur für konfigurierte RX-Blöcke)
    let pollCode = `
void lk_can_poll() {
  while (CAN.available()) {
    CanMsg const msg = CAN.read();
`;
    if (ArduinoGenerator.can_rx_handlers && ArduinoGenerator.can_rx_handlers.size > 0) {
        ArduinoGenerator.can_rx_handlers.forEach((data, uniqueId) => {
            const expectedId = (parseInt(data.mod) * 128) + parseInt(data.ch);
            pollCode += `    if (msg.id == ${expectedId}) {\n`;
            if (data.type === '0') {
                pollCode += `      lk_can_val_${uniqueId} = (float)msg.data[0];\n`;
            } else if (data.type === '1') {
                pollCode += `      int32_t temp; memcpy(&temp, msg.data, 4); lk_can_val_${uniqueId} = (float)temp;\n`;
            } else if (data.type === '2') {
                pollCode += `      int16_t temp; memcpy(&temp, msg.data, 2); lk_can_val_${uniqueId} = (float)temp / 10.0f;\n`;
            } else if (data.type === '3') {
                pollCode += `      float temp; memcpy(&temp, msg.data, 4); lk_can_val_${uniqueId} = temp;\n`;
            }
            pollCode += `      lk_can_flag_${uniqueId} = true;\n    }\n`;
        });
    }
    pollCode += `  }\n}`;
    ArduinoGenerator.globals_.add(pollCode);

    // Initialisierung & Background-Loop Einhängen
    ArduinoGenerator.autoSetup_.push(`
  if (!CAN.begin(CanBitRate::BR_250k)) {
    Serial.println("CAN Init Fehler");
  }
`);
    // Dieser Aufruf checkt jeden Zyklus den Buffer, blockiert aber nicht.
    ArduinoGenerator.autoLoop_.push(`  lk_can_poll();\n`);
    
    return '';
};

ArduinoGenerator.forBlock['can_send_cyclic'] = function(block) {
    const ch = block.getFieldValue('CHANNEL');
    const type = block.getFieldValue('TYPE');
    const interval = block.getFieldValue('INTERVAL');
    const valueCode = ArduinoGenerator.valueToCode(block, 'VAL', 0) || '0';
    
    const timerVar = `lk_can_timer_${ArduinoGenerator.mx_modules++}`;
    ArduinoGenerator.globals_.add(`unsigned long ${timerVar} = 0;`);
    
    return `
  if (millis() - ${timerVar} >= ${interval}) {
    ${timerVar} = millis();
    lk_can_send(lk_my_can_module_id, ${ch}, ${type}, (float)(${valueCode}));
  }\n`;
};

ArduinoGenerator.forBlock['can_send_change'] = function(block) {
    const ch = block.getFieldValue('CHANNEL');
    const type = block.getFieldValue('TYPE');
    const valueCode = ArduinoGenerator.valueToCode(block, 'VAL', 0) || '0';
    
    const lastVar = `lk_can_last_${ArduinoGenerator.mx_modules++}`;
    ArduinoGenerator.globals_.add(`float ${lastVar} = -99999.0;`);
    
    return `
  float _temp_val_${lastVar} = (float)(${valueCode});
  if (_temp_val_${lastVar} != ${lastVar}) {
    ${lastVar} = _temp_val_${lastVar};
    lk_can_send(lk_my_can_module_id, ${ch}, ${type}, _temp_val_${lastVar});
  }\n`;
};

ArduinoGenerator.forBlock['can_on_receive'] = function(block) {
    const mod = block.getFieldValue('MOD_ID');
    const ch = block.getFieldValue('CHANNEL');
    
    // Liest den echten Variablennamen aus dem Workspace aus
    const varName = Blockly.Variables.getVariable(block.workspace, block.getFieldValue('VAR')).name;
    const uniqueId = `${mod}_${ch}`;
    
    const innerCode = ArduinoGenerator.statementToCode(block, 'DO');
    
    return `
  if (lk_can_flag_${uniqueId}) {
    lk_can_flag_${uniqueId} = false;
    ${varName} = lk_can_val_${uniqueId};
${innerCode}
  }\n`;
};