/**
 * @license
 * Copyright 2017 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview Example "wait" block that will pause the interpreter for a
 * number of seconds. Because wait is a blocking behaviour, such blocks will
 * only work in interpreted environments.
 *
 * See https://neil.fraser.name/software/JS-Interpreter/docs.html
 */
Blockly.defineBlocksWithJsonArray([{
  "type": "wait_seconds1",
  "message0": "wait %1 milliseconds",
  "args0": [{
    "type": "field_number",
    "name": "SECONDS",
    "min": 0,
    "max": 60000,
    "value": 1000
  }],
  "previousStatement": null,
  "nextStatement": null,
  "colour": "#FFB347"
}]);

Blockly.defineBlocksWithJsonArray([{
  "type": "wait_seconds2",
  "message0": "wait %1 milliseconds",
  "args0": [{
    "type": "field_number",
    "name": "SECONDS",
    "min": 0,
    "max": 60000,
    "value": 2000
  }],
  "previousStatement": null,
  "nextStatement": null,
  "colour": "#FFB347"
}]);

Blockly.defineBlocksWithJsonArray([{
  "type": "wait_seconds3",
  "message0": "wait %1 milliseconds",
  "args0": [{
    "type": "field_number",
    "name": "SECONDS",
    "min": 0,
    "max": 60000,
    "value": 5000
  }],
  "previousStatement": null,
  "nextStatement": null,
  "colour": "#FFB347"
}]);

Blockly.defineBlocksWithJsonArray([{
  "type": "wait_seconds4",
  "message0": "wait %1 milliseconds",
  "args0": [{
    "type": "field_number",
    "name": "SECONDS",
    "min": 0,
    "max": 60000,
    "value": 10000
  }],
  "previousStatement": null,
  "nextStatement": null,
  "colour": "#FFB347"
}]);

Blockly.defineBlocksWithJsonArray([{
  "type": "change_speed",
  "message0": "set speed to %1%",
  "args0": [{
    "type": "field_number",
    "name": "SPEED",
    "value": 50,
    "min": 1,
    "max": 100
  }],
  "previousStatement": null,
  "nextStatement": null,
  "colour": "#9c27b0",
  "tooltip": "Change the speed",
  "helpUrl": ""
}]);

Blockly.defineBlocksWithJsonArray([
  {
    "type": "my_custom_block",
    "message0": "Check Distance (cm) %1 angle %2",
    "args0": [
      {
        "type": "field_number",
        "name": "DISTANCE",
        "check": "Number",
        "value": 40,
        "min": 20,
        "max": 200
      },
      {
        "type": "field_number",
        "name": "ANGLE",
        "value": 0,
        "min": -180,
        "max": 180
      }
    ],
    "output": "Boolean",
    "colour": 270,
    "tooltip": "returns true when distance reached",
    "helpUrl": ""
  }
]);

Blockly.JavaScript['my_custom_block'] = function(block) {
  const distance = 5 * Number(block.getFieldValue('DISTANCE'));
  const angle = Number(block.getFieldValue('ANGLE'));
  var code = 'checkDistance(' + distance + ', ' + angle + ')';
  return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};

async function checkDistance(distance, angle) {
  // Perform the distance check asynchronously and return a boolean value
  return new Promise(resolve => {
    setTimeout(() => {
      Manual.ultrasonicFlag = 'on';
      Manual.sendValue['US'] = ['on', angle];
      if (distance <= Manual.ultrasonicDist) {
        resolve(false);
      } else {
        resolve(true);
      }
    }, 50); // Simulate an asynchronous operation with a timeout
  });
}

function initInterpreterDistance(interpreter, globalObject) {
  // Register the checkDistance function with the interpreter as an asynchronous function
  const wrapper = interpreter.createAsyncFunction(async (distance, angle, callback) => {
    const result = await checkDistance(distance, angle);
    callback(result);
  });
  interpreter.setProperty(globalObject, 'checkDistance', wrapper);
}


/**
 * Generator for wait block creates call to new method
 * <code>waitForSeconds()</code>.
 */
Blockly.JavaScript['wait_seconds1'] = function(block) {
  const seconds = Number(block.getFieldValue('SECONDS'));
  const code = 'waitForMseconds(' + seconds + ');\n';
  return code;
};

Blockly.JavaScript['wait_seconds2'] = function(block) {
  const seconds = Number(block.getFieldValue('SECONDS'));
  const code = 'waitForMseconds(' + seconds + ');\n';
  return code;
};

Blockly.JavaScript['wait_seconds3'] = function(block) {
  const seconds = Number(block.getFieldValue('SECONDS'));
  const code = 'waitForMseconds(' + seconds + ');\n';
  return code;
};

Blockly.JavaScript['wait_seconds4'] = function(block) {
  const seconds = Number(block.getFieldValue('SECONDS'));
  const code = 'waitForMseconds(' + seconds + ');\n';
  return code;
};

Blockly.JavaScript['change_speed'] = function(block) {
  var speed = block.getFieldValue('SPEED');
  var code = "ManualSetSpeed('" + speed + "');\n";
  return code;
};

/**
 * Register the interpreter asynchronous function
 * <code>waitForSeconds()</code>.
 */

function initInterpreterWaitForSecondsStep(interpreter, globalObject) {
  // Ensure function name does not conflict with variable names.
  Blockly.JavaScript.addReservedWords('waitForMseconds');

  const wrapper0 = interpreter.createNativeFunction(
    function(timeInSeconds, callback) {
      callback;
    });
  interpreter.setProperty(globalObject, 'waitForMseconds', wrapper0);
}

function initInterpreterWaitForSeconds(interpreter, globalObject) {
  // Ensure function name does not conflict with variable names.
  Blockly.JavaScript.addReservedWords('waitForMseconds');

  const wrapper = interpreter.createAsyncFunction(
    function(timeInSeconds, callback) {
      // Delay the call to the callback.
      setTimeout(callback, timeInSeconds);    
    });
  interpreter.setProperty(globalObject, 'waitForMseconds', wrapper);
}

function initInterpreterMoveForward(interpreter, globalObject) {
  // Ensure function name does not conflict with variable names.
  Blockly.JavaScript.addReservedWords('upArrowEvent');

  const wrapper2 = interpreter.createNativeFunction(
    function(callback) {
      // Delay the call to the callback.      
      Manual.upArrowEvent();
      callback;
    });
  interpreter.setProperty(globalObject, 'upArrowEvent', wrapper2);
}

function initInterpreterMoveBackward(interpreter, globalObject) {
  // Ensure function name does not conflict with variable names.
  Blockly.JavaScript.addReservedWords('downArrowEvent');

  const wrapper3 = interpreter.createNativeFunction(
    function(callback) {    
      Manual.downArrowEvent();
      callback;
    });
  interpreter.setProperty(globalObject, 'downArrowEvent', wrapper3);
}

function initInterpreterTurnRight(interpreter, globalObject) {
  // Ensure function name does not conflict with variable names.
  Blockly.JavaScript.addReservedWords('rightArrowEvent');

  const wrapper4 = interpreter.createNativeFunction(
    function(callback) {    
      Manual.rightArrowEvent();
      callback;
    });
  interpreter.setProperty(globalObject, 'rightArrowEvent', wrapper4);
}

function initInterpreterTurnLeft(interpreter, globalObject) {
  // Ensure function name does not conflict with variable names.
  Blockly.JavaScript.addReservedWords('leftArrowEvent');

  const wrapper5 = interpreter.createNativeFunction(
    function(callback) {    
      Manual.leftArrowEvent();
      callback;
    });
  interpreter.setProperty(globalObject, 'leftArrowEvent', wrapper5);
}

function initInterpreterStopMotion(interpreter, globalObject) {
  // Ensure function name does not conflict with variable names.
  Blockly.JavaScript.addReservedWords('stop');

  const wrapper6 = interpreter.createNativeFunction(
    function(callback) {  
      //reset of the car 
      Manual.sendValue['US'] = [1];
      Manual.stop();
      Manual.sendValue['US'] = [0];
      callback;
    });
  interpreter.setProperty(globalObject, 'stop', wrapper6);
}

function initInterpreterSpeedChange(interpreter, globalObject) {
  // Ensure function name does not conflict with variable names.
  Blockly.JavaScript.addReservedWords('ManualSetSpeed');

  const wrapper7 = interpreter.createNativeFunction(
    function(speed, callback) {
      Manual.setSpeed(speed); 
      callback
    });
  interpreter.setProperty(globalObject, 'ManualSetSpeed', wrapper7);
}
