const inspector = require('node:inspector');
const path = require('node:path');
const { pathToFileURL } = require('node:url');

// This test case will set a breakpoint 4 lines below
function debuggedFunction () {
  let i;
  let accum = 0;
  for (i = 0; i < 5; i++) {
    accum += i;
  }
  return accum;
}

let scopeCallback = null;

function checkScope (session, scopeId) {
  session.post('Runtime.getProperties', {
    objectId: scopeId,
    ownProperties: false,
    accessorPropertiesOnly: false,
    generatePreview: true
  }, scopeCallback);
}

function debuggerPausedCallback (session, notification) {
  const params = notification.params;
  const callFrame = params.callFrames[0];
  const scopeId = callFrame.scopeChain[0].object.objectId;
  checkScope(session, scopeId);
}

function testSampleDebugSession () {
  let cur = 0;
  const failures = [];
  const expects = {
    i: [0, 1, 2, 3, 4],
    accum: [0, 0, 1, 3, 6]
  };
  scopeCallback = function (error, result) {
    if (error) failures.push(error);
    const i = cur++;
    let v, actual, expected;
    for (v of result.result) {
      actual = v.value.value;
      expected = expects[v.name][i];
      if (actual !== expected) {
        failures.push(`Iteration ${i} variable: ${v.name} ` +
          `expected: ${expected} actual: ${actual}`);
      }
    }
  };
  const session = new inspector.Session();
  session.connect();
  session.on('Debugger.paused',
    (notification) => debuggerPausedCallback(session, notification));
  let cbAsSecondArgCalled = false;
  session.post('Debugger.enable', () => { cbAsSecondArgCalled = true; });
  session.post('Debugger.setBreakpointByUrl', {
    lineNumber: 9,
    url: pathToFileURL(path.resolve(__dirname, __filename)).toString(),
    columnNumber: 0,
    condition: ''
  });

  debuggedFunction();
  scopeCallback = null;
  session.disconnect();
  process.send({
    cmd: 'assert',
    debuggerEnabled: cbAsSecondArgCalled,
    success: (cur === 5) && (failures.length === 0)
  });
}

testSampleDebugSession();