window.onload = function() {

  let workspace;
  const isWebView = window.chrome && window.chrome.webview;

  // === Debounce-Funktion ===
  let debounceTimeout;
  const debounce = (func, delay) => {
    return function(...args) {
      const context = this;
      clearTimeout(debounceTimeout);
      debounceTimeout = setTimeout(() => func.apply(context, args), delay);
    };
  };

  // === LLVM-IR-GENERATOR (FINALE VERSION) ===
  Blockly.LLVM = new Blockly.Generator('LLVM');
  Blockly.LLVM.ORDER_ATOMIC = 0;
  Blockly.LLVM.ORDER_NONE = 99;

  // --- Block-Definitionen für die Toolbox ---
  Blockly.defineBlocksWithJsonArray([
      {
        "type": "host_log_integer",
        "message0": "Logge Integer %1",
        "args0": [
          {
            "type": "input_value",
            "name": "VALUE",
            "check": "Number"
          }
        ],
        "previousStatement": null,
        "nextStatement": null,
        "colour": 290,
        "tooltip": "Sendet einen Integer-Wert an den Delphi-Host.",
        "helpUrl": ""
      },
      {
        "type": "host_get_integer_input",
        "message0": "Hole Integer-Eingabe von Host",
        "output": "Number",
        "colour": 290,
        "tooltip": "Liefert einen Integer-Wert, der vom Delphi-Host übergeben wurde.",
        "helpUrl": ""
      },
      {
        "type": "host_add_integers",
        "message0": "Addiere %1 und %2 auf Host",
        "args0": [
          {
            "type": "input_value",
            "name": "NUM1",
            "check": "Number"
          },
          {
            "type": "input_value",
            "name": "NUM2",
            "check": "Number"
          }
        ],
        "output": "Number",
        "colour": 290, // Host-Farbe
        "tooltip": "Addiert zwei Integer-Werte unter Verwendung einer Host-Funktion.",
        "helpUrl": ""
      }
  ]);

  // --- Generator-Implementierungen ---

  Blockly.LLVM.regCounter = 0;
  Blockly.LLVM.newReg = function() {
      return '%' + (Blockly.LLVM.regCounter++);
  };

  Blockly.LLVM.workspaceToCode = function(workspace) {
    Blockly.LLVM.regCounter = 1;
    Blockly.LLVM.generatedStrings = new Set();
    Blockly.LLVM.globalDeclarations = '';
    Blockly.LLVM.functionDeclarations = '';

    const allVariables = workspace.getAllVariables();
    let varAllocations = '';
    if (allVariables.length > 0) {
        allVariables.forEach(v => {
            const safeVarName = v.name.replace(/ /g, '_');
            varAllocations += `  @${safeVarName} = common global i32 0\n`;
        });
    }

    const topBlock = workspace.getTopBlocks(true)[0];
    const code = topBlock ? Blockly.LLVM.blockToCode(topBlock) : '';

    let moduleCode = `target triple = "x86_64-pc-windows-msvc"\n\n`;

    // NEU: Deklaration der Host-Funktion (Signatur, die der Host implementiert)
    moduleCode += `; Host Provided Function Declarations\n`;
    moduleCode += `declare i32 @host_add_integers_func(i32, i32)\n\n`; // Beispiel: Funktion, die zwei i32 nimmt und i32 zurückgibt

    if (Blockly.LLVM.functionDeclarations) {
        moduleCode += Blockly.LLVM.functionDeclarations + '\n';
    }

    moduleCode += `@gLogIntProc = common global void (i32)* null\n`;
    // NEU: Globaler Zeiger für die Host-Additionsfunktion
    moduleCode += `@gHostAddIntegersProc = common global i32 (i32, i32)* null\n\n`;


    if (varAllocations) {
        moduleCode += '; Global Variables\n';
        moduleCode += varAllocations + '\n';
    }

    // StarteLogik-Signatur erweitern, um den neuen Funktionszeiger-Parameter zu akzeptieren
    moduleCode += 'define dllexport void @StarteLogik(void (i32)* %LogIntProc, i32 %hostInputInteger, i32 (i32, i32)* %HostAddIntegersProc) {\n';
    moduleCode += 'entry:\n';
    moduleCode += '  store void (i32)* %LogIntProc, void (i32)** @gLogIntProc\n';
    // NEU: Den übergebenen Funktionszeiger in den globalen Zeiger speichern
    moduleCode += '  store i32 (i32, i32)* %HostAddIntegersProc, i32 (i32, i32)** @gHostAddIntegersProc\n\n';


    moduleCode += code.split('\n').map(line => line ? '  ' + line : '').join('\n');
    moduleCode += '\n  ret void\n';
    moduleCode += '}\n';
    return moduleCode;
  };


  Blockly.LLVM.scrub_ = function(block, code) {
      const nextBlock = block.nextConnection && block.nextConnection.targetBlock();
      const nextCode = nextBlock ? Blockly.LLVM.blockToCode(nextBlock) : '';
      return code + nextCode;
  };

  Blockly.LLVM.forBlock['variables_set'] = function(block) {
      const varName = block.workspace.getVariableById(block.getFieldValue('VAR')).name.replace(/ /g, '_');
      const value = Blockly.LLVM.valueToCode(block, 'VALUE', Blockly.LLVM.ORDER_ATOMIC) || '0';
      return `store i32 ${value}, i32* @${varName}\n`;
  };

  Blockly.LLVM.forBlock['math_change'] = function(block) {
      const varName = block.workspace.getVariableById(block.getFieldValue('VAR')).name.replace(/ /g, '_');
      const delta = Blockly.LLVM.valueToCode(block, 'DELTA', Blockly.LLVM.ORDER_ATOMIC) || '0';

      const loadReg = Blockly.LLVM.newReg();
      const addReg = Blockly.LLVM.newReg();

      let code = '';
      code += `${loadReg} = load i32, i32* @${varName}\n`;
      code += `${addReg} = add nsw i32 ${loadReg}, ${delta}\n`;
      code += `store i32 ${addReg}, i32* @${varName}\n`;
      return code;
  };

  Blockly.LLVM.forBlock['variables_get'] = function(block) {
      const varName = block.workspace.getVariableById(block.getFieldValue('VAR')).name.replace(/ /g, '_');
      return ['@' + varName, Blockly.LLVM.ORDER_ATOMIC];
  };

  Blockly.LLVM.forBlock['math_number'] = function(block) {
      return [String(block.getFieldValue('NUM')), Blockly.LLVM.ORDER_ATOMIC];
  };

  Blockly.LLVM.forBlock['host_log_integer'] = function(block) {
      const valueCode = Blockly.LLVM.valueToCode(block, 'VALUE', Blockly.LLVM.ORDER_ATOMIC) || '0';

      let valueReg;
      let code = '';

      if (valueCode.startsWith('@')) {
          valueReg = Blockly.LLVM.newReg();
          code += `${valueReg} = load i32, i32* ${valueCode}\n`;
      } else if (valueCode.startsWith('%')) {
          valueReg = valueCode;
      } else {
          valueReg = valueCode;
      }

      const logPtrReg = Blockly.LLVM.newReg();
      code += `${logPtrReg} = load void (i32)*, void (i32)** @gLogIntProc\n`;
      code += `call void ${logPtrReg}(i32 ${valueReg})\n`;
      return code;
  };

  Blockly.LLVM.forBlock['host_get_integer_input'] = function(block) {
    const inputParamReg = '%hostInputInteger';
    return [inputParamReg, Blockly.LLVM.ORDER_ATOMIC];
  };

Blockly.LLVM.forBlock['host_add_integers'] = function(block) {
  const num1 = Blockly.LLVM.valueToCode(block, 'NUM1', Blockly.LLVM.ORDER_ATOMIC) || '0';
  const num2 = Blockly.LLVM.valueToCode(block, 'NUM2', Blockly.LLVM.ORDER_ATOMIC) || '0';

  const funcPtrReg = Blockly.LLVM.newReg();
  const resultReg = Blockly.LLVM.newReg();

  let code = '';
  // Lade den globalen Funktionszeiger, der vom Host gesetzt wird
  code += `${funcPtrReg} = load i32 (i32, i32)*, i32 (i32, i32)** @gHostAddIntegersProc\n`;
  // Rufe die Host-Funktion auf
  code += `${resultReg} = call i32 ${funcPtrReg}(i32 ${num1}, i32 ${num2})\n`;

  return [code + resultReg, Blockly.LLVM.ORDER_ATOMIC];
};

  const toolboxXml = `
    <xml>
      <category name="Variablen" colour="%{BKY_VARIABLES_HUE}" custom="VARIABLE"></category>
      <category name="Mathematik" colour="%{BKY_MATH_HUE}">
        <block type="math_number"></block>
        <block type="math_change">
            <value name="DELTA"><shadow type="math_number"><field name="NUM">1</field></shadow></value>
        </block>
      </category>
      <category name="Host" colour="290">
        <block type="host_log_integer"></block>
        <block type="host_get_integer_input"></block>
        <block type="host_add_integers"></block>
      </category>
    </xml>`; // <--- DAS FEHLENDE BACKTICK HIER IST DIE LÖSUNG!

  workspace = Blockly.inject('blocklyDiv', {
    toolbox: toolboxXml,
    zoom: {
      controls: true,
      wheel: true,
      startScale: 1.0,
      maxScale: 3,
      minScale: 0.3,
      scaleSpeed: 1.2
    },
    trashcan: true,
    maxBlocks: 500,
    scrollbars: true,
    grid: {
      spacing: 25,
      length: 3,
      colour: '#eee',
      snap: true
    },
    comments: true,
    disable: true,
    collapse: true,
    readOnly: false
  });

  // --- Code-Generierungs- und Post-Funktion (angepasst, um vorher zu speichern) ---
  function generateAndPostCode() {
    // 1. Arbeitsbereich speichern
    const state = Blockly.serialization.workspaces.save(workspace);
    localStorage.setItem('blocklyWorkspace', JSON.stringify(state));
    // Optional: Konsolenmeldung zur automatischen Speicherung
    // console.log("Arbeitsbereich automatisch gespeichert vor Code-Generierung.");

    // 2. Code generieren
    const code = Blockly.LLVM.workspaceToCode(workspace);

    // 3. Code posten oder anzeigen
    if (isWebView) {
        if (window.chrome && window.chrome.webview) {
            window.chrome.webview.postMessage(code);
        }
    } else {
        document.getElementById('codeOutput').value = code;
        console.log("Code in Konsole ausgegeben (nicht im WebView):");
        console.log(code);
    }
  }
  window.generateAndPostCode = generateAndPostCode;

  window.saveWorkspace = function() {
    const state = Blockly.serialization.workspaces.save(workspace);
    localStorage.setItem('blocklyWorkspace', JSON.stringify(state));
    alert('Arbeitsbereich gespeichert!');
  }
  window.loadWorkspace = function() { const stateString = localStorage.getItem('blocklyWorkspace'); if (!stateString) { return; } const state = JSON.parse(stateString); Blockly.serialization.workspaces.load(state, workspace); }

  // --- Debounced-Funktion für die Code-Generierung ---
  // Die Generierung wird erst 500ms nach der letzten Änderung im Arbeitsbereich ausgelöst.
  const debouncedGenerateAndPostCode = debounce(generateAndPostCode, 500);

  // --- Dynamische Code-Aktualisierung / Posten (ruft debouncedGenerateAndPostCode auf) ---
  function handleCodeUpdate(event) {
    if (event.isUiEvent) return;
    debouncedGenerateAndPostCode();
  }
  workspace.addChangeListener(handleCodeUpdate);
  loadWorkspace();

  // --- Bedingte UI-Elemente und Splitter-Logik ---
  const outputContainer = document.getElementById('outputContainer');
  const blocklyDiv = document.getElementById('blocklyDiv');

  if (isWebView) {
    blocklyDiv.style.width = '100%';
    setTimeout(function() {
        Blockly.svgResize(workspace);
    }, 100);

    const buttonBar = document.querySelector('.button-bar');
    if (buttonBar) {
        const saveButton = buttonBar.querySelector('button[onclick="saveWorkspace()"]');
        const loadButton = buttonBar.querySelector('button[onclick="loadWorkspace()"]');
        if (saveButton) saveButton.remove();
        if (loadButton) loadButton.remove();
        const postButton = buttonBar.querySelector('button[onclick="generateAndPostCode()"]');
        if (postButton) postButton.remove();
    }

  } else {
    outputContainer.style.display = 'flex';

    const outputArea = document.getElementById('outputArea');
    const splitter = document.getElementById('splitter');
    const container = document.getElementById('container');

    let isDragging = false;

    splitter.addEventListener('mousedown', function(e) {
      isDragging = true;
      document.body.style.userSelect = 'none';
      document.body.style.cursor = 'ew-resize';
    });

    document.addEventListener('mousemove', function(e) {
      if (!isDragging) return;

      const containerRect = container.getBoundingClientRect();
      const splitterWidth = splitter.offsetWidth;
      const outputAreaMarginLeft = parseInt(window.getComputedStyle(outputArea).marginLeft);

      const totalContentWidth = containerRect.width - splitterWidth - outputAreaMarginLeft;
      let newBlocklyWidth = e.clientX - containerRect.left;

      const minBlocklyWidth = parseFloat(window.getComputedStyle(blocklyDiv).minWidth);
      const minOutputAreaWidth = parseFloat(window.getComputedStyle(outputArea).minWidth);

      if (newBlocklyWidth < minBlocklyWidth) {
          newBlocklyWidth = minBlocklyWidth;
      }

      let newOutputAreaWidth = totalContentWidth - newBlocklyWidth;

      if (newOutputAreaWidth < minOutputAreaWidth) {
          newOutputAreaWidth = minOutputAreaWidth;
          newBlocklyWidth = totalContentWidth - newOutputAreaWidth;
          if (newBlocklyWidth < minBlocklyWidth) {
              newBlocklyWidth = minBlocklyWidth;
          }
      }

      blocklyDiv.style.width = `${newBlocklyWidth}px`;
      outputArea.style.width = `${newOutputAreaWidth}px`;

      Blockly.svgResize(workspace);
    });

    document.addEventListener('mouseup', function() {
      isDragging = false;
      document.body.style.userSelect = '';
      document.body.style.cursor = '';
    });

    const initialOutputAreaWidth = 500;
    const totalFlexContentWidth = container.offsetWidth - splitter.offsetWidth - parseInt(window.getComputedStyle(outputArea).marginLeft);
    let initialBlocklyWidth = totalFlexContentWidth - initialOutputAreaWidth;

    const minBlocklyWidth = parseFloat(window.getComputedStyle(blocklyDiv).minWidth);

    if (initialBlocklyWidth < minBlocklyWidth) {
        initialBlocklyWidth = minBlocklyWidth;
        outputArea.style.width = `${totalFlexContentWidth - initialBlocklyWidth}px`;
    } else {
        outputArea.style.width = `${initialOutputAreaWidth}px`;
    }
    blocklyDiv.style.width = `${initialBlocklyWidth}px`;

    Blockly.svgResize(workspace);
  }
};
