// 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 '../builder/builder.dart';
import '../builder/declaration_builders.dart';
import 'scope.dart';

abstract class LocalScope implements LookupScope {
  @override
  ScopeKind get kind;

  LocalScope createNestedScope(
      {required String debugName, required ScopeKind kind});

  LocalScope createNestedFixedScope(
      {required String debugName,
      required Map<String, Builder> local,
      required ScopeKind kind});

  Iterable<Builder> get localVariables;

  Builder? lookupLocalVariable(String name);

  /// Declares that the meaning of [name] in this scope is [builder].
  ///
  /// If name was used previously in this scope, this method returns the read
  /// offsets which can be used for reporting a compile-time error about
  /// [name] being used before its declared.
  List<int>? declare(String name, Builder builder);

  void addLocalVariable(String name, Builder builder);

  @override
  Builder? lookupGetable(String name, int charOffset, Uri fileUri);

  @override
  Builder? lookupSetable(String name, int charOffset, Uri uri);

  Map<String, List<int>>? get usedNames;
}

abstract base class BaseLocalScope implements LocalScope {
  @override
  LocalScope createNestedScope(
      {required String debugName, required ScopeKind kind}) {
    return new LocalScopeImpl(this, kind, debugName);
  }

  @override
  LocalScope createNestedFixedScope(
      {required String debugName,
      required Map<String, Builder> local,
      required ScopeKind kind}) {
    return new FixedLocalScope(
        kind: kind, parent: this, local: local, debugName: debugName);
  }
}

mixin LocalScopeMixin implements LookupScopeMixin, LocalScope {
  LookupScope? get _parent;

  Map<String, Builder>? get _local;

  @override
  String get classNameOrDebugName;

  @override
  Iterable<Builder> get localVariables => _local?.values ?? const {};

  @override
  Builder? lookupGetable(String name, int charOffset, Uri fileUri) {
    _recordUse(name, charOffset);
    Builder? builder;
    if (_local != null) {
      builder = lookupGetableIn(name, charOffset, fileUri, _local!);
      if (builder != null) return builder;
    }
    return builder ?? _parent?.lookupGetable(name, charOffset, fileUri);
  }

  @override
  Builder? lookupLocalVariable(String name) {
    return _local?[name];
  }

  @override
  Builder? lookupSetable(String name, int charOffset, Uri fileUri) {
    _recordUse(name, charOffset);
    Builder? builder = lookupSetableIn(name, charOffset, fileUri, _local);
    return builder ?? _parent?.lookupSetable(name, charOffset, fileUri);
  }

  void _recordUse(String name, int charOffset) {}

  @override
  // Coverage-ignore(suite): Not run.
  void forEachExtension(void Function(ExtensionBuilder) f) {
    _parent?.forEachExtension(f);
  }
}

final class LocalScopeImpl extends BaseLocalScope
    with LookupScopeMixin, LocalScopeMixin
    implements LocalScope {
  @override
  final LocalScope? _parent;

  @override
  final String classNameOrDebugName;

  /// Names declared in this scope.
  @override
  Map<String, Builder>? _local;

  @override
  Map<String, List<int>>? usedNames;

  @override
  final ScopeKind kind;

  LocalScopeImpl(this._parent, this.kind, this.classNameOrDebugName);

  @override
  void addLocalVariable(String name, Builder builder) {
    (_local ??= {})[name] = builder;
  }

  @override
  List<int>? declare(String name, Builder builder) {
    List<int>? previousOffsets = usedNames?[name];
    if (previousOffsets != null && previousOffsets.isNotEmpty) {
      return previousOffsets;
    }
    (_local ??= {})[name] = builder;
    return null;
  }

  @override
  void _recordUse(String name, int charOffset) {
    usedNames ??= <String, List<int>>{};
    // Don't use putIfAbsent to avoid the context allocation needed
    // for the closure.
    (usedNames![name] ??= []).add(charOffset);
  }

  @override
  String toString() =>
      "$runtimeType(${kind}, $classNameOrDebugName, ${_local?.keys})";
}

mixin ImmutableLocalScopeMixin implements LocalScope {
  @override
  void addLocalVariable(String name, Builder builder) {
    throw new UnsupportedError('$runtimeType($kind).addLocalMember');
  }

  @override
  List<int>? declare(String name, Builder builder) {
    throw new UnsupportedError('$runtimeType($kind).declare');
  }

  @override
  // Coverage-ignore(suite): Not run.
  Map<String, List<int>>? get usedNames => null;
}

final class FixedLocalScope extends BaseLocalScope
    with LookupScopeMixin, ImmutableLocalScopeMixin, LocalScopeMixin {
  @override
  final LocalScope? _parent;
  @override
  final ScopeKind kind;
  @override
  final Map<String, Builder>? _local;

  final String _debugName;

  FixedLocalScope(
      {required this.kind,
      LocalScope? parent,
      Map<String, Builder>? local,
      required String debugName})
      : _parent = parent,
        _local = local,
        _debugName = debugName;

  @override
  String get classNameOrDebugName => _debugName;

  @override
  String toString() =>
      "$runtimeType(${kind}, $classNameOrDebugName, ${_local?.keys})";
}

final class FormalParameterScope extends BaseLocalScope
    with LookupScopeMixin, ImmutableLocalScopeMixin, LocalScopeMixin {
  @override
  final LookupScope? _parent;
  @override
  final Map<String, Builder>? _local;

  FormalParameterScope({LookupScope? parent, Map<String, Builder>? local})
      : _parent = parent,
        _local = local;

  @override
  ScopeKind get kind => ScopeKind.formals;

  @override
  String get classNameOrDebugName => "formal parameter";

  @override
  String toString() =>
      "$runtimeType(${kind}, $classNameOrDebugName, ${_local?.keys})";
}

final class EnclosingLocalScope extends BaseLocalScope
    with ImmutableLocalScopeMixin {
  final LookupScope _scope;

  EnclosingLocalScope(this._scope);

  @override
  ScopeKind get kind => _scope.kind;

  @override
  // Coverage-ignore(suite): Not run.
  Iterable<Builder> get localVariables => const [];

  @override
  Builder? lookupGetable(String name, int charOffset, Uri fileUri) {
    return _scope.lookupGetable(name, charOffset, fileUri);
  }

  @override
  // Coverage-ignore(suite): Not run.
  Builder? lookupLocalVariable(String name) => null;

  @override
  Builder? lookupSetable(String name, int charOffset, Uri uri) {
    return _scope.lookupSetable(name, charOffset, uri);
  }

  @override
  // Coverage-ignore(suite): Not run.
  void forEachExtension(void Function(ExtensionBuilder) f) {
    _scope.forEachExtension(f);
  }

  @override
  String toString() => "$runtimeType(${kind},$_scope)";
}
