// --- 1. DYNAMISCHES DROPDOWN EXTENSION ---
// Sammelt alle vergebenen Sensor-Namen aus dem Workspace
Blockly.Extensions.register('dynamic_ds18b20_dropdown', function() {
    this.getInput('MAIN').appendField(new Blockly.FieldDropdown(function() {
        let options = [];
        let ws = Blockly.getMainWorkspace(); 
        if (ws) {
            let blocks = ws.getAllBlocks(false);
            blocks.forEach(function(block) {
                if (block.type === 'ds18b20_name_by_index' || block.type === 'ds18b20_name_by_address') {
                    let name = block.getFieldValue('NAME');
                    if (name && name.trim() !== '') {
                        options.push([name, name]);
                    }
                }
            });
        }
        if (options.length === 0) {
            options.push(['- Keine Sensoren definiert -', 'NONE']);
        }
        return options;
    }), 'SENSOR_NAME');
});

// --- 2. BLOCK DEFINITIONEN (JSON) ---
Blockly.defineBlocksWithJsonArray([
    // MASTER SETUP
    {
        "type": "ds18b20_setup",
        "message0": "⚙️ DS18B20 Bus an PIN %1",
        "message1": "Intervall %1 ms | Auflösung %2",
        "message2": "Sensoren: %1",
        "args0": [{"type": "field_input", "name": "PIN", "text": "4"}],
        "args1": [
            {"type": "field_number", "name": "INTERVAL", "value": 2000, "min": 500},
            {"type": "field_dropdown", "name": "RESOLUTION", "options": [
                ["12-bit (0,0625 °C)", "12"], ["11-bit (0,125 °C)", "11"],
                ["10-bit (0,25 °C)", "10"], ["9-bit (0,5 °C)", "9"]
            ]}
        ],
        "args2": [{"type": "input_statement", "name": "SENSORS"}],
        "colour": 85,
        "tooltip": "Konfiguriert den OneWire Bus. Andocken der Sensor-Namen im inneren Bereich."
    },
    // ZUWEISUNG TYP A: INDEX
    {
        "type": "ds18b20_name_by_index",
        "message0": "Index %1 ➡️ Name %2",
        "args0": [
            {"type": "field_number", "name": "INDEX", "value": 0, "min": 0},
            {"type": "field_input", "name": "NAME", "text": "Verdampfer"}
        ],
        "previousStatement": null,
        "nextStatement": null,
        "colour": 85,
        "tooltip": "Weist dem Sensor über seine durchgezählte Nummer einen Namen zu."
    },
    // ZUWEISUNG TYP B: ADRESSE
    {
        "type": "ds18b20_name_by_address",
        "message0": "Adresse %1 ➡️ Name %2",
        "args0": [
            {"type": "field_input", "name": "ADDRESS", "text": "28FF4A1B..."},
            {"type": "field_input", "name": "NAME", "text": "Verdampfer"}
        ],
        "previousStatement": null,
        "nextStatement": null,
        "colour": 85,
        "tooltip": "Weist dem Sensor über seine feste Hex-Adresse einen Namen zu."
    },
    // LESE BLOCK (LOOP)
    {
        "type": "ds18b20_read",
        "message0": "🌡️ Temperatur von %1",
        "args0": [
            {"type": "input_dummy", "name": "MAIN"} // Dropdown wird hier über Extension injiziert
        ],
        "extensions": ["dynamic_ds18b20_dropdown"],
        "output": "Number",
        "colour": 85,
        "tooltip": "Gibt den zuletzt asynchron gemessenen Temperaturwert aus."
    },
    // DIAGNOSE BLOCK
    {
        "type": "ds18b20_diagnostic",
        "message0": "🔍 Diagnose One-Wire Bus an PIN %1",
        "args0": [{"type": "field_input", "name": "PIN", "text": "4"}],
        "previousStatement": null,
        "nextStatement": null,
        "colour": 160,
        "tooltip": "Dieser Block sollte ins SETUP. Gibt Adressen und Indizes im Serial Monitor (9600 Baud) aus."
    }
]);

// --- 3. HARDWARE SCANNERS & GENERATORS ---

// Master Setup Scanner
ArduinoGenerator.hardwareScanners['ds18b20_setup'] = function(block) {
    const rawPin = block.getFieldValue('PIN').trim();
    const safePin = rawPin.replace(/[^a-zA-Z0-9]/g, '');
    const interval = block.getFieldValue('INTERVAL');
    const resolution = block.getFieldValue('RESOLUTION');

    ArduinoGenerator.includes_.add('#include <OneWire.h>');
    ArduinoGenerator.includes_.add('#include <DallasTemperature.h>');

    ArduinoGenerator.globals_.add(`const int pin_ow_${safePin} = ${rawPin};`);
    ArduinoGenerator.globals_.add(`OneWire oneWire_${safePin}(pin_ow_${safePin});`);
    ArduinoGenerator.globals_.add(`DallasTemperature sensors_${safePin}(&oneWire_${safePin});`);

    ArduinoGenerator.autoSetup_.push(`  sensors_${safePin}.begin();\n`);
    ArduinoGenerator.autoSetup_.push(`  sensors_${safePin}.setResolution(${resolution});\n`);
    ArduinoGenerator.autoSetup_.push(`  sensors_${safePin}.setWaitForConversion(false);\n`);

    ArduinoGenerator.globals_.add(`unsigned long _ds18_lastReq_${safePin} = 0;`);
    ArduinoGenerator.globals_.add(`const int _ds18_interval_${safePin} = ${interval};`);
    
    ArduinoGenerator.globals_.add(`
void requestDS18_${safePin}() {
  if (millis() - _ds18_lastReq_${safePin} >= _ds18_interval_${safePin}) {
    sensors_${safePin}.requestTemperatures();
    _ds18_lastReq_${safePin} = millis();
  }
}
`);
};

ArduinoGenerator.forBlock['ds18b20_setup'] = function(block) {
    ArduinoGenerator.statementToCode(block, 'SENSORS');
    return ''; // Inline Code leer, alles wird via autoSetup und globals geregelt
};

// Generatoren für die Zuweisungen
ArduinoGenerator.forBlock['ds18b20_name_by_index'] = function(block) {
    return ''; // Index braucht keine globalen Arrays, wird im Lese-Block geregelt
};

ArduinoGenerator.forBlock['ds18b20_name_by_address'] = function(block) {
    let name = block.getFieldValue('NAME');
    // Filtere alles außer erlaubte Hex-Zeichen heraus (ignoriert also Leerzeichen etc.)
    let addr = block.getFieldValue('ADDRESS').replace(/[^A-F0-9]/gi, '').toUpperCase();
    
    if(addr.length === 16) {
        // Splittet den sauberen String in 2er Paare und setzt 0x davor
        let hexArray = addr.match(/.{1,2}/g).map(h => '0x' + h).join(', ');
        ArduinoGenerator.globals_.add(`DeviceAddress addr_${name} = { ${hexArray} };`);
    } else {
        ArduinoGenerator.globals_.add(`// FEHLER: Adresse für ${name} ist ungültig (muss 16 Zeichen lang sein)`);
    }
    return '';
};

// Lese-Block (Holt sich die Daten asynchron aus dem Cache)
ArduinoGenerator.forBlock['ds18b20_read'] = function(block) {
    let sensorName = block.getFieldValue('SENSOR_NAME');
    if(sensorName === 'NONE') return ['0.0', 0];

    // Finde heraus, wo dieser Name definiert wurde, um den PIN zu erhalten
    let ws = Blockly.getMainWorkspace();
    let allBlocks = ws.getAllBlocks(false);
    let targetBlock = null;
    for(let b of allBlocks) {
        if((b.type === 'ds18b20_name_by_index' || b.type === 'ds18b20_name_by_address') && b.getFieldValue('NAME') === sensorName) {
            targetBlock = b; 
            break;
        }
    }

    if(!targetBlock) return ['0.0', 0];

    let setupBlock = targetBlock.getSurroundParent();
    if(!setupBlock || setupBlock.type !== 'ds18b20_setup') return ['0.0', 0];

    let rawPin = setupBlock.getFieldValue('PIN').trim();
    const safePin = rawPin.replace(/[^a-zA-Z0-9]/g, '');

    let code = '';
    if(targetBlock.type === 'ds18b20_name_by_index') {
        let index = targetBlock.getFieldValue('INDEX');
        code = `(requestDS18_${safePin}(), sensors_${safePin}.getTempCByIndex(${index}))`;
    } else {
        code = `(requestDS18_${safePin}(), sensors_${safePin}.getTempC(addr_${sensorName}))`;
    }

    return [code, 0];
};

// Diagnose-Block Code
ArduinoGenerator.forBlock['ds18b20_diagnostic'] = function(block) {
    let rawPin = block.getFieldValue('PIN').trim();
    const safePin = rawPin.replace(/[^a-zA-Z0-9]/g, '');

    // Falls man die Diagnose startet ohne den Setup Block zu nutzen, laden wir die Libs mit
    ArduinoGenerator.includes_.add('#include <OneWire.h>');
    ArduinoGenerator.includes_.add('#include <DallasTemperature.h>');
    
    ArduinoGenerator.globals_.add(`const int pin_ow_diag_${safePin} = ${rawPin};`);
    ArduinoGenerator.globals_.add(`OneWire oneWire_diag_${safePin}(pin_ow_diag_${safePin});`);
    ArduinoGenerator.globals_.add(`DallasTemperature sensors_diag_${safePin}(&oneWire_diag_${safePin});`);

    let code = `
  Serial.begin(9600);
  sensors_diag_${safePin}.begin();
  int count_${safePin} = sensors_diag_${safePin}.getDeviceCount();
  Serial.println("--- OneWire Diagnose Start ---");
  for(int i = 0; i < count_${safePin}; i++) {
    DeviceAddress tempAddr;
    sensors_diag_${safePin}.getAddress(tempAddr, i);
    Serial.print("Index "); Serial.print(i);
    Serial.print(" = Adresse: ");
    for(uint8_t j = 0; j < 8; j++) {
      if(tempAddr[j] < 16) Serial.print("0");
      Serial.print(tempAddr[j], HEX);
    }
    sensors_diag_${safePin}.requestTemperatures();
    Serial.print(" | Aktuelle Temp: ");
    Serial.print(sensors_diag_${safePin}.getTempCByIndex(i));
    Serial.println(" °C");
  }
  Serial.println("--- Diagnose Ende ---");
`;
    return code;
};