// h-bridge Motor Driver addon
//
// Adds a "h-bridge Motor" toolbox category with:
//   - motor_init: set up a motor with IN1 and IN2 pins
//   - motor_speed: set speed from -255 (full reverse) to +255 (full forward)
//   - motor_stop: stop a motor
//
// Generates device-appropriate MicroPython:
//   - ESP32 / RP2040: machine.Pin + machine.PWM
//   - micro:bit: pinN.write_analog()

// --- Block definitions ---

api.Blockly.Blocks['hbridge_motor_init'] = {
  init() {
    this.appendDummyInput()
      .appendField('init motor')
      .appendField(new api.Blockly.FieldDropdown([
        ['A', 'A'],
        ['B', 'B'],
      ]), 'MOTOR')
      .appendField('IN1 pin')
      .appendField(new api.Blockly.FieldNumber(2, 0, 48, 1), 'IN1')
      .appendField('IN2 pin')
      .appendField(new api.Blockly.FieldNumber(3, 0, 48, 1), 'IN2');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Initialize an h-bridge motor channel with two pins');
  },
};

api.Blockly.Blocks['hbridge_motor_speed'] = {
  init() {
    this.appendDummyInput()
      .appendField('set motor')
      .appendField(new api.Blockly.FieldDropdown([
        ['A', 'A'],
        ['B', 'B'],
      ]), 'MOTOR');
    this.appendValueInput('SPEED')
      .setCheck('Number')
      .appendField('speed');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Set motor speed: -255 (full reverse) to +255 (full forward)');
  },
};

api.Blockly.Blocks['hbridge_motor_stop'] = {
  init() {
    this.appendDummyInput()
      .appendField('stop motor')
      .appendField(new api.Blockly.FieldDropdown([
        ['A', 'A'],
        ['B', 'B'],
      ]), 'MOTOR');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Stop an h-bridge motor (brake)');
  },
};

// --- Helpers used by generators ---

function isMicrobit() {
  return api.getDeviceId() === 'microbit';
}

function mbPin(pin) {
  var n = Math.max(0, Math.min(20, parseInt(pin, 10) || 0));
  return 'pin' + n;
}

// --- Code generators ---

api.pythonGenerator.forBlock['hbridge_motor_init'] = function (block) {
  var motor = block.getFieldValue('MOTOR');
  var in1 = block.getFieldValue('IN1');
  var in2 = block.getFieldValue('IN2');
  var m = motor.toLowerCase();

  if (isMicrobit()) {
    // micro:bit: no explicit init needed, just store pin numbers for later use.
    // We define variables so speed/stop blocks can reference them.
    api.pythonGenerator.definitions_['import_microbit'] = 'from microbit import *';
    api.pythonGenerator.definitions_['hb_motor_' + m + '_pins'] =
      'motor_' + m + '_in1 = ' + mbPin(in1) + '\n' +
      'motor_' + m + '_in2 = ' + mbPin(in2);
    api.pythonGenerator.definitions_['hb_set_motor_mb'] = [
      'def _hb_set_motor(p1, p2, speed):',
      '    speed = max(-255, min(255, int(speed)))',
      '    duty = abs(speed) * 4',
      '    if speed > 0:',
      '        p1.write_analog(duty)',
      '        p2.write_analog(0)',
      '    elif speed < 0:',
      '        p1.write_analog(0)',
      '        p2.write_analog(duty)',
      '    else:',
      '        p1.write_analog(0)',
      '        p2.write_analog(0)',
    ].join('\n');
  } else {
    // ESP32 / RP2040: machine.PWM
    api.pythonGenerator.definitions_['import_machine'] =
      'from machine import Pin, PWM';
    api.pythonGenerator.definitions_['hb_motor_' + m + '_in1'] =
      'motor_' + m + '_in1 = PWM(Pin(' + in1 + '), freq=1000, duty=0)';
    api.pythonGenerator.definitions_['hb_motor_' + m + '_in2'] =
      'motor_' + m + '_in2 = PWM(Pin(' + in2 + '), freq=1000, duty=0)';
    api.pythonGenerator.definitions_['hb_set_motor'] = [
      'def _hb_set_motor(pwm1, pwm2, speed):',
      '    speed = max(-255, min(255, int(speed)))',
      '    duty = abs(speed) * 4',
      '    if speed > 0:',
      '        pwm1.duty(duty)',
      '        pwm2.duty(0)',
      '    elif speed < 0:',
      '        pwm1.duty(0)',
      '        pwm2.duty(duty)',
      '    else:',
      '        pwm1.duty(0)',
      '        pwm2.duty(0)',
    ].join('\n');
  }
  return '';
};

api.pythonGenerator.forBlock['hbridge_motor_speed'] = function (block) {
  var motor = block.getFieldValue('MOTOR');
  var m = motor.toLowerCase();
  var speed = api.pythonGenerator.valueToCode(
    block, 'SPEED', api.pythonGenerator.ORDER_NONE
  ) || '0';
  return '_hb_set_motor(motor_' + m + '_in1, motor_' + m + '_in2, ' + speed + ')\n';
};

api.pythonGenerator.forBlock['hbridge_motor_stop'] = function (block) {
  var motor = block.getFieldValue('MOTOR');
  var m = motor.toLowerCase();
  return '_hb_set_motor(motor_' + m + '_in1, motor_' + m + '_in2, 0)\n';
};

// --- Register toolbox category ---

api.registerCategories([
  {
    kind: 'category',
    name: 'H-Bridge Motor',
    colour: '30',
    contents: [
      { kind: 'block', type: 'hbridge_motor_init' },
      {
        kind: 'block',
        type: 'hbridge_motor_speed',
        inputs: {
          SPEED: { shadow: { type: 'math_number', fields: { NUM: 200 } } },
        },
      },
      { kind: 'block', type: 'hbridge_motor_stop' },
    ],
  },
]);
