// Copyright (c) 2020, 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 'package:dwds/src/debugging/location.dart';

const maxValue = 2147483647;

class SkipLists {
  // Map of script ID to scriptList.
  final _idToList = <String, List<Map<String, dynamic>>>{};

  void initialize() => _idToList.clear();

  /// Returns a skipList as defined by the Chrome DevTools Protocol.
  ///
  /// A `skipList` is an array of `LocationRange`s see:
  /// https://chromedevtools.github.io/devtools-protocol/tot/Debugger/#method-stepInto
  ///
  /// Can return a cached value.
  List<Map<String, dynamic>> compute(
    String scriptId,
    Set<Location> locations,
  ) {
    if (_idToList.containsKey(scriptId)) return _idToList[scriptId]!;

    final sortedLocations = locations.toList()
      ..sort((a, b) => a.jsLocation.compareTo(b.jsLocation));

    final ranges = <Map<String, dynamic>>[];
    var startLine = 0;
    var startColumn = 0;
    for (final location in sortedLocations) {
      var endLine = location.jsLocation.line;
      var endColumn = location.jsLocation.column;
      // Stop before the known location.
      endColumn -= 1;
      if (endColumn < 0) {
        endLine -= 1;
        endColumn = maxValue;
      }
      if (endLine > startLine || endColumn > startColumn) {
        if (endLine >= startLine) {
          ranges.add(
            _rangeFor(scriptId, startLine, startColumn, endLine, endColumn),
          );
        }
        startLine = location.jsLocation.line;
        startColumn = location.jsLocation.column + 1;
      }
    }
    ranges.add(_rangeFor(scriptId, startLine, startColumn, maxValue, maxValue));

    _idToList[scriptId] = ranges;
    return ranges;
  }

  Map<String, dynamic> _rangeFor(
    String scriptId,
    int startLine,
    int startColumn,
    int endLine,
    int endColumn,
  ) =>
      {
        'scriptId': scriptId,
        'start': {'lineNumber': startLine, 'columnNumber': startColumn},
        'end': {'lineNumber': endLine, 'columnNumber': endColumn},
      };
}
