// Copyright (c) 2024, 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/scanner/token.dart';
import 'package:kernel/ast.dart';

import '../base/export.dart';
import '../base/identifiers.dart';
import '../base/import.dart';
import '../base/problems.dart';
import '../codes/cfe_codes.dart';
import '../fragment/fragment.dart';

/// Map from offsets of directives and declarations to the objects the define.
///
/// This is used to connect parsing of the [OutlineBuilder], where the objects
/// are created, with the [DietListener], where the objects are looked up.
class OffsetMap {
  final Uri uri;
  final Map<int, DeclarationFragmentImpl> _declarations = {};
  final Map<int, FieldFragment> _fields = {};
  final Map<int, PrimaryConstructorFragment> _primaryConstructors = {};
  final Map<int, ConstructorFragment> _constructors = {};
  final Map<int, FactoryFragment> _factoryFragments = {};
  final Map<int, GetterFragment> _getters = {};
  final Map<int, SetterFragment> _setters = {};
  final Map<int, MethodFragment> _methods = {};
  final Map<int, LibraryPart> _parts = {};
  final Map<int, Import> _imports = {};
  final Map<int, Export> _exports = {};

  OffsetMap(this.uri);

  void registerImport(Token importKeyword, Import import) {
    assert(
      importKeyword.lexeme == 'import',
      "Invalid token for import: $importKeyword.",
    );
    _imports[importKeyword.charOffset] = import;
  }

  Import lookupImport(Token importKeyword) {
    assert(
      importKeyword.lexeme == 'import',
      "Invalid token for import: $importKeyword.",
    );
    return _checkDirective(
      _imports[importKeyword.charOffset],
      '<import>',
      importKeyword.charOffset,
    );
  }

  void registerExport(Token exportKeyword, Export export) {
    assert(
      exportKeyword.lexeme == 'export',
      "Invalid token for export: $exportKeyword.",
    );
    _exports[exportKeyword.charOffset] = export;
  }

  Export lookupExport(Token exportKeyword) {
    assert(
      exportKeyword.lexeme == 'export',
      "Invalid token for export: $exportKeyword.",
    );
    return _checkDirective(
      _exports[exportKeyword.charOffset],
      '<export>',
      exportKeyword.charOffset,
    );
  }

  void registerPart(Token partKeyword, LibraryPart part) {
    assert(
      partKeyword.lexeme == 'part',
      "Invalid token for part: $partKeyword.",
    );
    _parts[partKeyword.charOffset] = part;
  }

  LibraryPart lookupPart(Token partKeyword) {
    assert(
      partKeyword.lexeme == 'part',
      "Invalid token for part: $partKeyword.",
    );
    return _checkDirective(
      _parts[partKeyword.charOffset],
      '<part>',
      partKeyword.charOffset,
    );
  }

  void registerNamedDeclarationFragment(
    Identifier identifier,
    DeclarationFragmentImpl fragment,
  ) {
    _declarations[identifier.nameOffset] = fragment;
  }

  DeclarationFragmentImpl lookupNamedDeclaration(Identifier identifier) {
    return _checkFragment(
      _declarations[identifier.nameOffset],
      identifier.name,
      identifier.nameOffset,
    );
  }

  void registerUnnamedDeclaration(
    Token beginToken,
    DeclarationFragmentImpl fragment,
  ) {
    _declarations[beginToken.charOffset] = fragment;
  }

  DeclarationFragmentImpl lookupUnnamedDeclaration(Token beginToken) {
    return _checkFragment(
      _declarations[beginToken.charOffset],
      '<unnamed-declaration>',
      beginToken.charOffset,
    );
  }

  void registerField(Identifier identifier, FieldFragment fragment) {
    _fields[identifier.nameOffset] = fragment;
  }

  FieldFragment lookupField(Identifier identifier) {
    return _checkFragment(
      _fields[identifier.nameOffset],
      identifier.name,
      identifier.nameOffset,
    );
  }

  void registerPrimaryConstructor(
    Token beginToken,
    PrimaryConstructorFragment fragment,
  ) {
    _primaryConstructors[beginToken.charOffset] = fragment;
  }

  FunctionFragment lookupPrimaryConstructor(Token beginToken) {
    return _checkFragment(
      _primaryConstructors[beginToken.charOffset],
      '<primary-constructor>',
      beginToken.charOffset,
    );
  }

  void registerConstructorFragment(
    Identifier identifier,
    ConstructorFragment fragment,
  ) {
    _constructors[identifier.nameOffset] = fragment;
  }

  void registerFactoryFragment(
    Identifier identifier,
    FactoryFragment fragment,
  ) {
    _factoryFragments[identifier.nameOffset] = fragment;
  }

  FunctionFragment lookupConstructor(Identifier identifier) {
    FunctionFragment? fragment = _constructors[identifier.nameOffset];
    fragment ??= _factoryFragments[identifier.nameOffset];
    return _checkFragment(fragment, identifier.name, identifier.nameOffset);
  }

  void registerGetter(Identifier identifier, GetterFragment fragment) {
    _getters[identifier.nameOffset] = fragment;
  }

  void registerSetter(Identifier identifier, SetterFragment fragment) {
    _setters[identifier.nameOffset] = fragment;
  }

  void registerMethod(Identifier identifier, MethodFragment fragment) {
    _methods[identifier.nameOffset] = fragment;
  }

  FunctionFragment lookupGetter(Identifier identifier) {
    return _checkFragment(
      _getters[identifier.nameOffset],
      identifier.name,
      identifier.nameOffset,
    );
  }

  FunctionFragment lookupSetter(Identifier identifier) {
    return _checkFragment(
      _setters[identifier.nameOffset],
      identifier.name,
      identifier.nameOffset,
    );
  }

  FunctionFragment lookupMethod(Identifier identifier) {
    return _checkFragment(
      _methods[identifier.nameOffset],
      identifier.name,
      identifier.nameOffset,
    );
  }

  T _checkDirective<T>(T? directive, String name, int charOffset) {
    if (directive == null) {
      internalProblem(
        codeInternalProblemNotFound.withArguments(name),
        charOffset,
        uri,
      );
    }
    return directive;
  }

  T _checkFragment<T>(T? fragment, String name, int fileOffset) {
    if (fragment == null) {
      internalProblem(
        codeInternalProblemNotFound.withArguments(name),
        fileOffset,
        uri,
      );
    }
    return fragment;
  }
}
