import * as Blockly from 'blockly';
import { FieldPitch } from './field_pitch.js';

// ─── Pin I/O ──────────────────────────────────────────────

Blockly.Blocks['pin_set_mode'] = {
  init() {
    this.appendDummyInput()
      .appendField('set pin')
      .appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
      .appendField('as')
      .appendField(new Blockly.FieldDropdown([
        ['OUTPUT', 'OUT'],
        ['INPUT', 'IN'],
        ['INPUT_PULLUP', 'PULL_UP'],
      ]), 'MODE');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(230);
    this.setTooltip('Configure a GPIO pin mode');
  },
};

Blockly.Blocks['pin_digital_write'] = {
  init() {
    this.appendDummyInput()
      .appendField('digital write pin')
      .appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
      .appendField('to')
      .appendField(new Blockly.FieldDropdown([
        ['HIGH', '1'],
        ['LOW', '0'],
      ]), 'VALUE');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(230);
    this.setTooltip('Write HIGH or LOW to a digital pin');
  },
};

Blockly.Blocks['pin_digital_read'] = {
  init() {
    this.appendDummyInput()
      .appendField('digital read pin')
      .appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN');
    this.setOutput(true, 'Number');
    this.setColour(230);
    this.setTooltip('Read digital value from a pin (0 or 1)');
  },
};

// ─── PWM ──────────────────────────────────────────────────

Blockly.Blocks['pwm_init'] = {
  init() {
    this.appendDummyInput()
      .appendField('init PWM on pin')
      .appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
      .appendField('freq')
      .appendField(new Blockly.FieldNumber(1000, 1, 40000000, 1), 'FREQ')
      .appendField('Hz');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(160);
    this.setTooltip('Initialize PWM on a pin with a frequency');
  },
};

Blockly.Blocks['pwm_set_duty'] = {
  init() {
    this.appendValueInput('DUTY')
      .setCheck('Number')
      .appendField('set PWM duty on pin')
      .appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
      .appendField('to');
    this.appendDummyInput()
      .appendField('(0-1023)');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(160);
    this.setTooltip('Set PWM duty cycle (0-1023)');
  },
};

Blockly.Blocks['pwm_set_freq'] = {
  init() {
    this.appendValueInput('FREQ')
      .setCheck('Number')
      .appendField('set PWM freq on pin')
      .appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
      .appendField('to');
    this.appendDummyInput()
      .appendField('Hz');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(160);
    this.setTooltip('Set PWM frequency in Hz');
  },
};

// ─── ADC ──────────────────────────────────────────────────

Blockly.Blocks['adc_read'] = {
  init() {
    this.appendDummyInput()
      .appendField('read ADC on pin')
      .appendField(new Blockly.FieldNumber(1, 0, 20, 1), 'PIN');
    this.setOutput(true, 'Number');
    this.setColour(30);
    this.setTooltip('Read analog value from ADC pin (0-4095)');
  },
};

// ─── Time ─────────────────────────────────────────────────

Blockly.Blocks['sleep_seconds'] = {
  init() {
    this.appendValueInput('SECONDS')
      .setCheck('Number')
      .appendField('sleep');
    this.appendDummyInput()
      .appendField('seconds');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(120);
    this.setTooltip('Pause execution for N seconds');
  },
};

Blockly.Blocks['sleep_ms'] = {
  init() {
    this.appendValueInput('MS')
      .setCheck('Number')
      .appendField('sleep');
    this.appendDummyInput()
      .appendField('milliseconds');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(120);
    this.setTooltip('Pause execution for N milliseconds');
  },
};

Blockly.Blocks['ticks_ms'] = {
  init() {
    this.appendDummyInput()
      .appendField('ticks (ms)');
    this.setOutput(true, 'Number');
    this.setColour(120);
    this.setTooltip('Get millisecond tick counter');
  },
};

// ─── Random ───────────────────────────────────────────────

Blockly.Blocks['random_int'] = {
  init() {
    this.appendValueInput('FROM')
      .setCheck('Number')
      .appendField('random integer from');
    this.appendValueInput('TO')
      .setCheck('Number')
      .appendField('to');
    this.setOutput(true, 'Number');
    this.setInputsInline(true);
    this.setColour(200);
    this.setTooltip('Random integer N where from ≤ N ≤ to (inclusive)');
  },
};

Blockly.Blocks['random_float'] = {
  init() {
    this.appendDummyInput()
      .appendField('random float (0.0 to 1.0)');
    this.setOutput(true, 'Number');
    this.setColour(200);
    this.setTooltip('Random float in range [0.0, 1.0)');
  },
};

Blockly.Blocks['random_uniform'] = {
  init() {
    this.appendValueInput('LOW')
      .setCheck('Number')
      .appendField('random float from');
    this.appendValueInput('HIGH')
      .setCheck('Number')
      .appendField('to');
    this.setOutput(true, 'Number');
    this.setInputsInline(true);
    this.setColour(200);
    this.setTooltip('Random float in range [low, high]');
  },
};

Blockly.Blocks['random_seed'] = {
  init() {
    this.appendValueInput('SEED')
      .setCheck('Number')
      .appendField('random seed');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(200);
    this.setTooltip('Set random seed for reproducible sequences (optional)');
  },
};

// ─── WiFi ─────────────────────────────────────────────────

Blockly.Blocks['wifi_connect'] = {
  init() {
    this.appendDummyInput()
      .appendField('connect WiFi SSID')
      .appendField(new Blockly.FieldTextInput('MyNetwork'), 'SSID')
      .appendField('password')
      .appendField(new Blockly.FieldTextInput('password'), 'PASSWORD');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(290);
    this.setTooltip('Connect to a WiFi network');
  },
};

Blockly.Blocks['wifi_get_ip'] = {
  init() {
    this.appendDummyInput()
      .appendField('WiFi IP address');
    this.setOutput(true, 'String');
    this.setColour(290);
    this.setTooltip('Get the current IP address');
  },
};

// ─── NeoPixel ─────────────────────────────────────────────

Blockly.Blocks['neopixel_init'] = {
  init() {
    this.appendDummyInput()
      .appendField('init NeoPixel on pin')
      .appendField(new Blockly.FieldNumber(48, 0, 48, 1), 'PIN')
      .appendField('with')
      .appendField(new Blockly.FieldNumber(1, 1, 1024, 1), 'NUM')
      .appendField('LEDs');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(10);
    this.setTooltip('Initialize a NeoPixel strip');
  },
};

Blockly.Blocks['colour_rgb'] = {
  init() {
    this.appendValueInput('R').setCheck('Number').appendField('colour R');
    this.appendValueInput('G').setCheck('Number').appendField('G');
    this.appendValueInput('B').setCheck('Number').appendField('B');
    this.setOutput(true, 'Colour');
    this.setInputsInline(true);
    this.setColour(10);
    this.setTooltip('RGB colour as array [R, G, B] (values 0–255)');
  },
};

Blockly.Blocks['tuple_create_3'] = {
  init() {
    this.appendValueInput('A').appendField('tuple');
    this.appendValueInput('B').appendField(',');
    this.appendValueInput('C').appendField(',');
    this.setOutput(true, 'Colour');
    this.setInputsInline(true);
    this.setColour(10);
    this.setTooltip('Create a 3-element tuple (e.g. for NeoPixel colour). Use numbers or variables.');
  },
};

Blockly.Blocks['tuple_index'] = {
  init() {
    this.appendValueInput('TUPLE')
      .setCheck(null)
      .appendField('item')
      .appendField(
        new Blockly.FieldDropdown([
          ['0', '0'],
          ['1', '1'],
          ['2', '2'],
        ]),
        'I',
      )
      .appendField('of tuple');
    this.setOutput(true, 'Number');
    this.setInputsInline(true);
    this.setColour(10);
    this.setTooltip(
      'Read one element from a tuple by index. Use with the TCS34725 block or any (a, b, c) value.',
    );
  },
};

Blockly.Blocks['neopixel_set_color'] = {
  init() {
    this.appendValueInput('INDEX')
      .setCheck('Number')
      .appendField('set NeoPixel #');
    this.appendValueInput('COLOR')
      .setCheck(null)
      .appendField('colour');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(10);
    this.setTooltip('Set NeoPixel to a colour. Use the colour/tuple block or a variable (e.g. from a function parameter).');
  },
};

Blockly.Blocks['neopixel_show'] = {
  init() {
    this.appendDummyInput()
      .appendField('NeoPixel show');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(10);
    this.setTooltip('Push color data to NeoPixel strip');
  },
};

// ─── I2C ──────────────────────────────────────────────────
// Hardware I2C peripheral id (0 or 1). Generated code uses i2c0 / i2c1 variables.
const I2C_CHANNEL_OPTIONS = [
  ['ch 0', '0'],
  ['ch 1', '1'],
];

Blockly.Blocks['i2c_init'] = {
  init() {
    this.appendDummyInput()
      .appendField('init I2C')
      .appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
      .appendField('SDA pin')
      .appendField(new Blockly.FieldNumber(8, 0, 48, 1), 'SDA')
      .appendField('SCL pin')
      .appendField(new Blockly.FieldNumber(9, 0, 48, 1), 'SCL')
      .appendField('freq')
      .appendField(new Blockly.FieldNumber(400000, 1, 1000000, 1), 'FREQ');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(200);
    this.setTooltip('Initialize an I2C bus. ESP32/RP2040: channel 0 or 1 maps to I2C(0) or I2C(1).');
  },
};

Blockly.Blocks['i2c_scan'] = {
  init() {
    this.appendDummyInput()
      .appendField('I2C')
      .appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
      .appendField('scan devices');
    this.setOutput(true, 'Array');
    this.setColour(200);
    this.setTooltip('Scan for I2C devices on the selected bus, returns list of addresses');
  },
};

Blockly.Blocks['i2c_writeto'] = {
  init() {
    this.appendValueInput('DATA')
      .setCheck(null)
      .appendField('I2C')
      .appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
      .appendField('write to address')
      .appendField(new Blockly.FieldNumber(0, 0, 127, 1), 'ADDR')
      .appendField('data');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(200);
    this.setTooltip('Write data bytes to an I2C device on the selected bus');
  },
};

Blockly.Blocks['i2c_readfrom'] = {
  init() {
    this.appendDummyInput()
      .appendField('I2C')
      .appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
      .appendField('read from address')
      .appendField(new Blockly.FieldNumber(0, 0, 127, 1), 'ADDR')
      .appendField('bytes')
      .appendField(new Blockly.FieldNumber(1, 1, 256, 1), 'NBYTES');
    this.setOutput(true, null);
    this.setColour(200);
    this.setTooltip('Read N bytes from an I2C device on the selected bus');
  },
};

Blockly.Blocks['tcs34725_read_colours'] = {
  init() {
    this.appendDummyInput()
      .appendField('TCS34725 read RGB')
      .appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
      .appendField('address')
      .appendField(new Blockly.FieldNumber(41, 1, 127, 1), 'ADDR');
    this.setOutput(true, null);
    this.setColour(65);
    this.setTooltip(
      'Read raw RGB channel counts as (R, G, B), each 0–65535. If there is no init I2C block for this channel, the bus is set up on GPIO 21 (SDA) and 22 (SCL) at 400 kHz.',
    );
  },
};

// ─── HID (Keyboard / Mouse / Gamepad) ─────────────────────
// USB HID key codes (Usage Page 0x07). Value is decimal for generator.
const HID_KEY_OPTIONS = [
  ['A', '4'], ['B', '5'], ['C', '6'], ['D', '7'], ['E', '8'], ['F', '9'], ['G', '10'],
  ['H', '11'], ['I', '12'], ['J', '13'], ['K', '14'], ['L', '15'], ['M', '16'], ['N', '17'],
  ['O', '18'], ['P', '19'], ['Q', '20'], ['R', '21'], ['S', '22'], ['T', '23'], ['U', '24'],
  ['V', '25'], ['W', '26'], ['X', '27'], ['Y', '28'], ['Z', '29'],
  ['1', '30'], ['2', '31'], ['3', '32'], ['4', '33'], ['5', '34'],
  ['6', '35'], ['7', '36'], ['8', '37'], ['9', '38'], ['0', '39'],
  ['Enter', '40'], ['Esc', '41'], ['Backspace', '42'], ['Tab', '43'], ['Space', '44'],
  ['-', '45'], ['=', '46'], ['[', '47'], [']', '48'], ['\\', '49'], [';', '51'],
  ["'", '52'], ['`', '53'], [',', '54'], ['.', '55'], ['/', '56'],
  ['F1', '58'], ['F2', '59'], ['F3', '60'], ['F4', '61'], ['F5', '62'],
  ['F6', '63'], ['F7', '64'], ['F8', '65'], ['F9', '66'], ['F10', '67'], ['F11', '68'], ['F12', '69'],
];

Blockly.Blocks['hid_key_press'] = {
  init() {
    this.appendDummyInput()
      .appendField('HID key press')
      .appendField(new Blockly.FieldDropdown(HID_KEY_OPTIONS), 'KEY');
    this.appendDummyInput()
      .appendField('modifier')
      .appendField(new Blockly.FieldDropdown([
        ['none', '0'], ['Ctrl', '1'], ['Shift', '2'], ['Alt', '4'], ['GUI/Win', '8'],
        ['Ctrl+Shift', '3'], ['Ctrl+Alt', '5'], ['Shift+Alt', '6'],
      ]), 'MOD');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(330);
    this.setTooltip('Press and release a key (keyboard HID)');
  },
};

Blockly.Blocks['hid_key_down'] = {
  init() {
    this.appendDummyInput()
      .appendField('HID key down')
      .appendField(new Blockly.FieldDropdown(HID_KEY_OPTIONS), 'KEY');
    this.appendDummyInput()
      .appendField('modifier')
      .appendField(new Blockly.FieldDropdown([
        ['none', '0'], ['Ctrl', '1'], ['Shift', '2'], ['Alt', '4'], ['GUI/Win', '8'],
      ]), 'MOD');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(330);
    this.setTooltip('Hold key down (keyboard HID)');
  },
};

Blockly.Blocks['hid_key_up'] = {
  init() {
    this.appendDummyInput().appendField('HID key up (release all)');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(330);
    this.setTooltip('Release all keyboard keys');
  },
};

Blockly.Blocks['hid_keyboard_type'] = {
  init() {
    this.appendValueInput('TEXT')
      .setCheck('String')
      .appendField('HID type text');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(330);
    this.setTooltip('Type a string as keyboard input (HID)');
  },
};

Blockly.Blocks['hid_mouse_move'] = {
  init() {
    this.appendValueInput('X').setCheck('Number').appendField('HID mouse move X');
    this.appendValueInput('Y').setCheck('Number').appendField('Y');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(330);
    this.setTooltip('Move mouse relative (pixels)');
  },
};

Blockly.Blocks['hid_mouse_click'] = {
  init() {
    this.appendDummyInput()
      .appendField('HID mouse click')
      .appendField(new Blockly.FieldDropdown([
        ['left', '1'], ['right', '2'], ['middle', '4'],
      ]), 'BUTTON');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(330);
    this.setTooltip('Click mouse button (press and release)');
  },
};

Blockly.Blocks['hid_mouse_scroll'] = {
  init() {
    this.appendValueInput('DELTA')
      .setCheck('Number')
      .appendField('HID mouse scroll');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(330);
    this.setTooltip('Scroll wheel (positive = up, negative = down)');
  },
};

Blockly.Blocks['hid_gamepad_button'] = {
  init() {
    this.appendDummyInput()
      .appendField('HID gamepad button')
      .appendField(new Blockly.FieldDropdown([
        ['1', '0'], ['2', '1'], ['3', '2'], ['4', '3'], ['5', '4'], ['6', '5'],
        ['7', '6'], ['8', '7'], ['9', '8'], ['10', '9'], ['11', '10'], ['12', '11'],
        ['13', '12'], ['14', '13'], ['15', '14'], ['16', '15'],
      ]), 'BTN');
    this.appendDummyInput()
      .appendField(new Blockly.FieldDropdown([
        ['press', '1'],
        ['release', '0'],
      ]), 'STATE');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(330);
    this.setTooltip('Set gamepad button state (1-16)');
  },
};

Blockly.Blocks['hid_gamepad_axis'] = {
  init() {
    this.appendDummyInput()
      .appendField('HID gamepad axis')
      .appendField(new Blockly.FieldDropdown([
        ['left X', '0'], ['left Y', '1'], ['right X', '2'], ['right Y', '3'],
        ['left trigger', '4'], ['right trigger', '5'],
      ]), 'AXIS');
    this.appendValueInput('VALUE')
      .setCheck('Number')
      .appendField('value');
    this.appendDummyInput().appendField('(-127 to 127)');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(330);
    this.setTooltip('Set gamepad axis (-127 to 127, 0 = center)');
  },
};

// ─── Print ────────────────────────────────────────────────

Blockly.Blocks['print_text'] = {
  init() {
    this.appendValueInput('TEXT')
      .setCheck(null)
      .appendField('print');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(60);
    this.setTooltip('Print to serial output');
  },
};

// ─── H-Bridge Motor ─────────────────────────────────────

Blockly.Blocks['hbridge_motor_init'] = {
  init() {
    this.appendDummyInput()
      .appendField('init motor')
      .appendField(new Blockly.FieldDropdown([['A', 'A'], ['B', 'B']]), 'MOTOR')
      .appendField('IN1 pin')
      .appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'IN1')
      .appendField('IN2 pin')
      .appendField(new 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.');
  },
};

Blockly.Blocks['hbridge_motor_speed'] = {
  init() {
    this.appendDummyInput()
      .appendField('set motor')
      .appendField(new 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).');
  },
};

Blockly.Blocks['hbridge_motor_stop'] = {
  init() {
    this.appendDummyInput()
      .appendField('stop motor')
      .appendField(new 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).');
  },
};

Blockly.Blocks['hbridge_dual_init'] = {
  init() {
    this.appendDummyInput().appendField('init dual motors');
    this.appendDummyInput()
      .appendField('left IN1')
      .appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'L_IN1')
      .appendField('IN2')
      .appendField(new Blockly.FieldNumber(3, 0, 48, 1), 'L_IN2');
    this.appendDummyInput()
      .appendField('right IN1')
      .appendField(new Blockly.FieldNumber(4, 0, 48, 1), 'R_IN1')
      .appendField('IN2')
      .appendField(new Blockly.FieldNumber(5, 0, 48, 1), 'R_IN2');
    this.setInputsInline(false);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Initialize two h-bridge motors (left and right) with 4 pins.');
  },
};

Blockly.Blocks['hbridge_dual_speed'] = {
  init() {
    this.appendDummyInput().appendField('set motors');
    this.appendValueInput('LEFT')
      .setCheck('Number')
      .appendField('left');
    this.appendValueInput('RIGHT')
      .setCheck('Number')
      .appendField('right');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Set left and right motor speeds independently (-255 to 255).');
  },
};

Blockly.Blocks['hbridge_dual_forward'] = {
  init() {
    this.appendDummyInput().appendField('drive forward');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Drive both motors forward using the speed from "set motors".');
  },
};

Blockly.Blocks['hbridge_dual_backward'] = {
  init() {
    this.appendDummyInput().appendField('drive backward');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Drive both motors backward using the speed from "set motors".');
  },
};

Blockly.Blocks['hbridge_dual_left'] = {
  init() {
    this.appendDummyInput().appendField('turn left');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Turn left (left motor backward, right motor forward).');
  },
};

Blockly.Blocks['hbridge_dual_right'] = {
  init() {
    this.appendDummyInput().appendField('turn right');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Turn right (left motor forward, right motor backward).');
  },
};

Blockly.Blocks['hbridge_dual_forward_x_seconds'] = {
  init() {
    this.appendValueInput('SECS')
      .setCheck('Number')
      .appendField('drive forward for');
    this.appendDummyInput().appendField('seconds');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Drive forward for a number of seconds, then stop.');
  },
};

Blockly.Blocks['hbridge_dual_backward_x_seconds'] = {
  init() {
    this.appendValueInput('SECS')
      .setCheck('Number')
      .appendField('drive backward for');
    this.appendDummyInput().appendField('seconds');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Drive backward for a number of seconds, then stop.');
  },
};

Blockly.Blocks['hbridge_dual_left_x_seconds'] = {
  init() {
    this.appendValueInput('SECS')
      .setCheck('Number')
      .appendField('turn left for');
    this.appendDummyInput().appendField('seconds');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Turn left for a number of seconds, then stop.');
  },
};

Blockly.Blocks['hbridge_dual_right_x_seconds'] = {
  init() {
    this.appendValueInput('SECS')
      .setCheck('Number')
      .appendField('turn right for');
    this.appendDummyInput().appendField('seconds');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Turn right for a number of seconds, then stop.');
  },
};

Blockly.Blocks['hbridge_dual_stop'] = {
  init() {
    this.appendDummyInput().appendField('stop motors');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(30);
    this.setTooltip('Stop both motors.');
  },
};

// ─── Sound ───────────────────────────────────────────────

const NOTE_FREQUENCIES = [
  ['C4', '262'],
  ['C#4', '277'],
  ['D4', '294'],
  ['D#4', '311'],
  ['E4', '330'],
  ['F4', '349'],
  ['F#4', '370'],
  ['G4', '392'],
  ['G#4', '415'],
  ['A4', '440'],
  ['A#4', '466'],
  ['B4', '494'],
  ['C5', '523'],
  ['C#5', '554'],
  ['D5', '587'],
  ['D#5', '622'],
  ['E5', '659'],
  ['F5', '698'],
  ['F#5', '740'],
  ['G5', '784'],
  ['G#5', '831'],
  ['A5', '880'],
  ['A#5', '932'],
  ['B5', '988'],
];

Blockly.Blocks['sound_play_tone_speaker'] = {
  init() {
    this.appendDummyInput().appendField('play tone on speaker');
    this.appendValueInput('FREQ')
      .setCheck('Number')
      .appendField('freq');
    this.appendDummyInput().appendField('Hz');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput()
      .appendField('ms')
      .appendField(new Blockly.FieldDropdown([
        ['wait', 'TRUE'],
        ['continue', 'FALSE'],
      ]), 'WAIT');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a tone on the built-in speaker (micro:bit v2). "continue" runs code while tone plays.');
  },
};

Blockly.Blocks['sound_stop_speaker'] = {
  init() {
    this.appendDummyInput().appendField('stop speaker');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Stop sound on the built-in speaker (micro:bit v2)');
  },
};

Blockly.Blocks['sound_play_tone'] = {
  init() {
    this.appendDummyInput()
      .appendField('play tone on pin')
      .appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
    this.appendValueInput('FREQ')
      .setCheck('Number')
      .appendField('freq');
    this.appendDummyInput().appendField('Hz');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput()
      .appendField('ms')
      .appendField(new Blockly.FieldDropdown([
        ['wait', 'TRUE'],
        ['continue', 'FALSE'],
      ]), 'WAIT');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a tone via PWM on a specific pin. "continue" runs code while tone plays.');
  },
};

Blockly.Blocks['sound_stop'] = {
  init() {
    this.appendDummyInput()
      .appendField('stop sound on pin')
      .appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Stop sound on a specific pin');
  },
};

Blockly.Blocks['sound_play_note_speaker'] = {
  init() {
    this.appendDummyInput()
      .appendField('play note on speaker');
    this.appendDummyInput()
      .appendField('note')
      .appendField(new Blockly.FieldDropdown(NOTE_FREQUENCIES), 'NOTE');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput()
      .appendField('ms')
      .appendField(new Blockly.FieldDropdown([
        ['wait', 'TRUE'],
        ['continue', 'FALSE'],
      ]), 'WAIT');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a musical note on the built-in speaker (micro:bit v2).');
  },
};

Blockly.Blocks['sound_play_note'] = {
  init() {
    this.appendDummyInput()
      .appendField('play note on pin')
      .appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
    this.appendDummyInput()
      .appendField('note')
      .appendField(new Blockly.FieldDropdown(NOTE_FREQUENCIES), 'NOTE');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput()
      .appendField('ms')
      .appendField(new Blockly.FieldDropdown([
        ['wait', 'TRUE'],
        ['continue', 'FALSE'],
      ]), 'WAIT');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a musical note on a specific pin.');
  },
};

Blockly.Blocks['sound_play_staff_note_speaker'] = {
  init() {
    this.appendDummyInput()
      .appendField('play note on speaker');
    this.appendDummyInput()
      .appendField('note')
      .appendField(new FieldPitch('440'), 'NOTE');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput()
      .appendField('ms')
      .appendField(new Blockly.FieldDropdown([
        ['wait', 'TRUE'],
        ['continue', 'FALSE'],
      ]), 'WAIT');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a note on the built-in speaker, picked from a staff.');
  },
};

Blockly.Blocks['sound_play_staff_note'] = {
  init() {
    this.appendDummyInput()
      .appendField('play note on pin')
      .appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
    this.appendDummyInput()
      .appendField('note')
      .appendField(new FieldPitch('440'), 'NOTE');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput()
      .appendField('ms')
      .appendField(new Blockly.FieldDropdown([
        ['wait', 'TRUE'],
        ['continue', 'FALSE'],
      ]), 'WAIT');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a note on a specific pin, picked from a staff.');
  },
};

// ─── Sound – buzzer (init + pin-free blocks) ─────────────

Blockly.Blocks['sound_buzzer_init'] = {
  init() {
    this.appendDummyInput()
      .appendField('set up buzzer on pin')
      .appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Initialise a buzzer on a pin. Use with the "buzzer" play / stop blocks.');
  },
};

Blockly.Blocks['sound_buzzer_tone'] = {
  init() {
    this.appendDummyInput().appendField('play tone on buzzer');
    this.appendValueInput('FREQ')
      .setCheck('Number')
      .appendField('freq');
    this.appendDummyInput().appendField('Hz');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput()
      .appendField('ms')
      .appendField(new Blockly.FieldDropdown([
        ['wait', 'TRUE'],
        ['continue', 'FALSE'],
      ]), 'WAIT');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a tone on the buzzer (set pin with "set up buzzer" block).');
  },
};

Blockly.Blocks['sound_buzzer_note'] = {
  init() {
    this.appendDummyInput()
      .appendField('play note on buzzer')
      .appendField('note')
      .appendField(new Blockly.FieldDropdown(NOTE_FREQUENCIES), 'NOTE');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput()
      .appendField('ms')
      .appendField(new Blockly.FieldDropdown([
        ['wait', 'TRUE'],
        ['continue', 'FALSE'],
      ]), 'WAIT');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a musical note on the buzzer (set pin with "set up buzzer" block).');
  },
};

Blockly.Blocks['sound_buzzer_staff_note'] = {
  init() {
    this.appendDummyInput()
      .appendField('play note on buzzer')
      .appendField('note')
      .appendField(new FieldPitch('440'), 'NOTE');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput()
      .appendField('ms')
      .appendField(new Blockly.FieldDropdown([
        ['wait', 'TRUE'],
        ['continue', 'FALSE'],
      ]), 'WAIT');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a note (from staff) on the buzzer (set pin with "set up buzzer" block).');
  },
};

Blockly.Blocks['sound_buzzer_stop'] = {
  init() {
    this.appendDummyInput().appendField('stop buzzer');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Stop the buzzer (set pin with "set up buzzer" block).');
  },
};

// ─── Sound – melodies ────────────────────────────────────

Blockly.Blocks['sound_melody_mario'] = {
  init() {
    this.appendDummyInput()
      .appendField('play Mario theme on pin')
      .appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play the Super Mario Bros theme on a specific pin.');
  },
};

Blockly.Blocks['sound_melody_mario_buzzer'] = {
  init() {
    this.appendDummyInput().appendField('play Mario theme on buzzer');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play the Super Mario Bros theme on the buzzer (set pin with "set up buzzer" block).');
  },
};

Blockly.Blocks['sound_melody_happy'] = {
  init() {
    this.appendDummyInput()
      .appendField('play happy tune on pin')
      .appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a cheerful melody on a specific pin.');
  },
};

Blockly.Blocks['sound_melody_happy_buzzer'] = {
  init() {
    this.appendDummyInput().appendField('play happy tune on buzzer');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a cheerful melody on the buzzer (set pin with "set up buzzer" block).');
  },
};

Blockly.Blocks['sound_melody_sad'] = {
  init() {
    this.appendDummyInput()
      .appendField('play sad tune on pin')
      .appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a melancholy melody on a specific pin.');
  },
};

Blockly.Blocks['sound_melody_sad_buzzer'] = {
  init() {
    this.appendDummyInput().appendField('play sad tune on buzzer');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a melancholy melody on the buzzer (set pin with "set up buzzer" block).');
  },
};

// ─── micro:bit Display ────────────────────────────────────

// Helper to add one row of 5 checkboxes (Pxy = pixel at row x, col y)
function addMicrobitDisplayRow(block, row) {
  const input = block.appendDummyInput(`ROW${row}`);
  for (let col = 0; col < 5; col++) {
    const name = `P${row}${col}`;
    input.appendField(new Blockly.FieldCheckbox(false), name);
  }
}

Blockly.Blocks['microbit_display_all'] = {
  init() {
    this.appendDummyInput()
      .appendField('micro:bit display 5×5');
    for (let row = 0; row < 5; row++) {
      addMicrobitDisplayRow(this, row);
    }
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(10);
    this.setTooltip('Click LEDs to set the 5×5 display (micro:bit only). On = 9, off = 0.');
  },
};

// ─── SuperBit (Yahboom SuperBit V2, micro:bit only) ───────

Blockly.Blocks['superbit_motor_run'] = {
  init() {
    this.appendDummyInput()
      .appendField('SuperBit motor')
      .appendField(new Blockly.FieldDropdown([
        ['M1', 'M1'],
        ['M2', 'M2'],
        ['M3', 'M3'],
        ['M4', 'M4'],
      ]), 'MOTOR');
    this.appendValueInput('SPEED')
      .setCheck('Number')
      .appendField('speed (-255 to 255)');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(45);
    this.setTooltip('Run a SuperBit V2 motor (PCA9685 over I2C). Negative = reverse.');
  },
};

Blockly.Blocks['superbit_motor_stop_all'] = {
  init() {
    this.appendDummyInput()
      .appendField('SuperBit motor stop all');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(45);
    this.setTooltip('Stop all four SuperBit V2 motors.');
  },
};

// ─── Sensors (HC-SR04 style sonar, all devices) ───────────

Blockly.Blocks['sonar_distance'] = {
  init() {
    this.appendValueInput('TRIG')
      .setCheck('Number')
      .appendField('sonar distance trigger');
    this.appendValueInput('ECHO')
      .setCheck('Number')
      .appendField('echo');
    this.setInputsInline(true);
    this.setOutput(true, 'Number');
    this.setColour(65);
    this.setTooltip('HC-SR04 style ultrasonic distance in cm. Trigger and echo pin numbers.');
  },
};

// ─── Arduino-specific blocks ──────────────────────────────

Blockly.Blocks['arduino_builtin_led'] = {
  init() {
    this.appendDummyInput()
      .appendField('set built-in LED')
      .appendField(new Blockly.FieldDropdown([
        ['ON', '1'],
        ['OFF', '0'],
      ]), 'STATE');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(230);
    this.setTooltip('Turn the built-in LED (pin 13) on or off');
  },
};

Blockly.Blocks['arduino_analog_write'] = {
  init() {
    this.appendValueInput('VALUE')
      .setCheck('Number')
      .appendField('analog write pin')
      .appendField(new Blockly.FieldDropdown([
        ['3', '3'], ['5', '5'], ['6', '6'],
        ['9', '9'], ['10', '10'], ['11', '11'],
      ]), 'PIN')
      .appendField('value');
    this.appendDummyInput().appendField('(0-255)');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(160);
    this.setTooltip('Write a PWM value (0-255) to a PWM-capable pin');
  },
};

Blockly.Blocks['arduino_analog_read'] = {
  init() {
    this.appendDummyInput()
      .appendField('analog read')
      .appendField(new Blockly.FieldDropdown([
        ['A0', '0'], ['A1', '1'], ['A2', '2'],
        ['A3', '3'], ['A4', '4'], ['A5', '5'],
      ]), 'CHANNEL');
    this.setOutput(true, 'Number');
    this.setColour(30);
    this.setTooltip('Read analog value from an ADC channel (0-1023)');
  },
};

Blockly.Blocks['arduino_servo_attach'] = {
  init() {
    this.appendDummyInput()
      .appendField('attach servo on pin')
      .appendField(new Blockly.FieldDropdown([
        ['9', '9'], ['10', '10'], ['11', '11'],
        ['3', '3'], ['5', '5'], ['6', '6'],
      ]), 'PIN');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(260);
    this.setTooltip('Attach a servo motor to a PWM pin');
  },
};

Blockly.Blocks['arduino_servo_write'] = {
  init() {
    this.appendValueInput('ANGLE')
      .setCheck('Number')
      .appendField('set servo on pin')
      .appendField(new Blockly.FieldDropdown([
        ['9', '9'], ['10', '10'], ['11', '11'],
        ['3', '3'], ['5', '5'], ['6', '6'],
      ]), 'PIN')
      .appendField('to');
    this.appendDummyInput().appendField('degrees');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(260);
    this.setTooltip('Set servo angle (0-180 degrees)');
  },
};

Blockly.Blocks['arduino_tone'] = {
  init() {
    this.appendDummyInput()
      .appendField('play tone on pin')
      .appendField(new Blockly.FieldNumber(8, 0, 13, 1), 'PIN');
    this.appendValueInput('FREQ')
      .setCheck('Number')
      .appendField('freq');
    this.appendDummyInput().appendField('Hz');
    this.appendValueInput('DURATION')
      .setCheck('Number')
      .appendField('for');
    this.appendDummyInput().appendField('ms');
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Play a tone on a digital pin using PWM');
  },
};

Blockly.Blocks['arduino_no_tone'] = {
  init() {
    this.appendDummyInput()
      .appendField('stop tone on pin')
      .appendField(new Blockly.FieldNumber(8, 0, 13, 1), 'PIN');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(300);
    this.setTooltip('Stop any tone playing on a digital pin');
  },
};

// ─── Loops ─────────────────────────────────────────────

Blockly.Blocks['controls_repeat_forever'] = {
  init() {
    this.appendDummyInput().appendField('repeat forever');
    this.appendStatementInput('DO').appendField('do');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(120);
    this.setTooltip('Repeat the enclosed blocks forever.');
  },
};

Blockly.Blocks['arduino_map'] = {
  init() {
    this.appendValueInput('VALUE').setCheck('Number').appendField('map');
    this.appendValueInput('FROM_LOW').setCheck('Number').appendField('from');
    this.appendValueInput('FROM_HIGH').setCheck('Number').appendField('-');
    this.appendValueInput('TO_LOW').setCheck('Number').appendField('to');
    this.appendValueInput('TO_HIGH').setCheck('Number').appendField('-');
    this.setInputsInline(true);
    this.setOutput(true, 'Number');
    this.setColour(200);
    this.setTooltip('Re-map a number from one range to another');
  },
};
