// Copyright (c) 2014, 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:_fe_analyzer_shared/src/base/errors.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag;

typedef TodoDiagnosticCode =
    DiagnosticWithArguments<
      LocatableDiagnostic Function({required String message})
    >;

/// Static helper methods and properties for working with [DiagnosticType.TODO]
/// codes.
class Todo {
  static const _codes = {
    'TODO': diag.todo,
    'FIXME': diag.fixme,
    'HACK': diag.hack,
    'UNDONE': diag.undone,
  };

  /// This matches the two common Dart task styles
  ///
  /// * `TODO`:
  /// * `TODO`(username):
  ///
  /// As well as
  /// * `TODO`
  ///
  /// But not
  // * `todo`
  /// * `TODOS`
  ///
  /// It also supports wrapped TODOs where the next line is indented by a space:
  ///
  ///   /**
  ///    * `TODO`(username): This line is
  ///    *  wrapped onto the next line
  ///    */
  ///
  /// The matched kind of the `TODO` (`TODO`, `FIXME`, etc.) is returned in named
  /// captures of "kind1", "kind2" (since it is not possible to reuse a name
  /// across different parts of the regex).
  static RegExp TODO_REGEX = RegExp(
    '([\\s/\\*])(((?<kind1>$_TODO_KIND_PATTERN)[^\\w\\d][^\\r\\n]*(?:\\n\\s*\\*  [^\\r\\n]*)*)'
    '|((?<kind2>$_TODO_KIND_PATTERN):?\$))',
  );

  static final _TODO_KIND_PATTERN = _codes.keys.join('|');

  Todo._() {
    throw UnimplementedError('Do not construct');
  }

  /// Returns the TodoCode for [kind], falling back to [diag.todo].
  static TodoDiagnosticCode forKind(String kind) => _codes[kind] ?? diag.todo;
}
