// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:developer';

import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';

import 'common/expect.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';

// AUTOGENERATED START
//
// Update these constants by running:
//
// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
//
const LINE_A = 27;
const LINE_B = 35;
const LINE_C = 38;
const LINE_D = 41;
// AUTOGENERATED END

num Function() testFunction() {
  debugger(); // LINE_A
  late int a;
  try {
    late int b;
    try {
      for (final int i = 0; i < 10;) {
        // ignore: prefer_function_declarations_over_variables
        int x() => i + a + b;
        return x; // LINE_B
      }
    } finally {
      b = 10; // LINE_C
    }
  } finally {
    a = 1; // LINE_D
  }
  throw StateError('Unreachable');
}

void testMain() {
  final f = testFunction();
  Expect.equals(f(), 11);
}

final tests = <IsolateTest>[
  hasStoppedAtBreakpoint,
  stoppedAtLine(LINE_A),
  // Add breakpoint
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    var isolate = await service.getIsolate(isolateId);
    final rootLib =
        await service.getObject(isolateId, isolate.rootLib!.id!) as Library;

    final scriptId = rootLib.scripts![0].id!;
    final script = await service.getObject(isolateId, scriptId) as Script;

    // Add 3 breakpoints.
    {
      final bpt = await service.addBreakpoint(isolateId, script.id!, LINE_B);
      expect(bpt.location!.script!.id, scriptId);
      expect(script.getLineNumberFromTokenPos(bpt.location!.tokenPos), LINE_B);

      isolate = await service.getIsolate(isolateId);
      expect(isolate.breakpoints!.length, 1);
    }

    {
      final bpt = await service.addBreakpoint(isolateId, scriptId, LINE_C);
      expect(bpt.location!.script!.id, scriptId);
      expect(script.getLineNumberFromTokenPos(bpt.location!.tokenPos), LINE_C);

      isolate = await service.getIsolate(isolateId);
      expect(isolate.breakpoints!.length, 2);
    }

    {
      final bpt = await service.addBreakpoint(isolateId, scriptId, LINE_D);
      expect(bpt.location!.script!.id, scriptId);
      expect(script.getLineNumberFromTokenPos(bpt.location!.tokenPos), LINE_D);

      isolate = await service.getIsolate(isolateId);
      expect(isolate.breakpoints!.length, 3);
    }

    // Wait for breakpoint events.
  },

  resumeIsolate,

  hasStoppedAtBreakpoint,

  // We are at the breakpoint on line LINE_B.
  stoppedAtLine(LINE_B),

  resumeIsolate,

  hasStoppedAtBreakpoint,

  // We are at the breakpoint on line LINE_C.
  stoppedAtLine(LINE_C),

  resumeIsolate,

  hasStoppedAtBreakpoint,

  // We are at the breakpoint on line LINE_D.
  stoppedAtLine(LINE_D),

  resumeIsolate,
];

void main(List<String> args) => runIsolateTests(
      args,
      tests,
      'debugging_inlined_finally_test.dart',
      testeeConcurrent: testMain,
    );
