// Copyright 2014 The Flutter Authors. 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:collection';

import 'package:flutter/foundation.dart';

import 'framework.dart';
import 'notification_listener.dart';
import 'scroll_notification.dart';
import 'scroll_position.dart';

// Examples can assume:
// void _listener(ScrollNotification notification) { }
// late BuildContext context;

/// A [ScrollNotification] listener for [ScrollNotificationObserver].
///
/// [ScrollNotificationObserver] is similar to
/// [NotificationListener]. It supports a listener list instead of
/// just a single listener and its listeners run unconditionally, they
/// do not require a gating boolean return value.
typedef ScrollNotificationCallback = void Function(ScrollNotification notification);

class _ScrollNotificationObserverScope extends InheritedWidget {
  const _ScrollNotificationObserverScope({
    required super.child,
    required ScrollNotificationObserverState scrollNotificationObserverState,
  }) : _scrollNotificationObserverState = scrollNotificationObserverState;

  final ScrollNotificationObserverState  _scrollNotificationObserverState;

  @override
  bool updateShouldNotify(_ScrollNotificationObserverScope old) => _scrollNotificationObserverState != old._scrollNotificationObserverState;
}

class _ListenerEntry extends LinkedListEntry<_ListenerEntry> {
  _ListenerEntry(this.listener);
  final ScrollNotificationCallback listener;
}

/// Notifies its listeners when a descendant scrolls.
///
/// To add a listener to a [ScrollNotificationObserver] ancestor:
///
/// ```dart
/// ScrollNotificationObserver.of(context)!.addListener(_listener);
/// ```
///
/// To remove the listener from a [ScrollNotificationObserver] ancestor:
///
/// ```dart
/// ScrollNotificationObserver.of(context)!.removeListener(_listener);
/// ```
///
/// Stateful widgets that share an ancestor [ScrollNotificationObserver] typically
/// add a listener in [State.didChangeDependencies] (removing the old one
/// if necessary) and remove the listener in their [State.dispose] method.
///
/// Any function with the [ScrollNotificationCallback] signature can act as a
/// listener:
///
/// ```dart
/// // (e.g. in a stateful widget)
/// void _listener(ScrollNotification notification) {
///   // Do something, maybe setState()
/// }
/// ```
///
/// This widget is similar to [NotificationListener]. It supports a listener
/// list instead of just a single listener and its listeners run
/// unconditionally, they do not require a gating boolean return value.
class ScrollNotificationObserver extends StatefulWidget {
  /// Create a [ScrollNotificationObserver].
  ///
  /// The [child] parameter must not be null.
  const ScrollNotificationObserver({
    super.key,
    required this.child,
  }) : assert(child != null);

  /// The subtree below this widget.
  final Widget child;

  /// The closest instance of this class that encloses the given context.
  ///
  /// If there is no enclosing [ScrollNotificationObserver] widget, then null is returned.
  static ScrollNotificationObserverState? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<_ScrollNotificationObserverScope>()?._scrollNotificationObserverState;
  }

  @override
  ScrollNotificationObserverState createState() => ScrollNotificationObserverState();
}

/// The listener list state for a [ScrollNotificationObserver] returned by
/// [ScrollNotificationObserver.of].
///
/// [ScrollNotificationObserver] is similar to
/// [NotificationListener]. It supports a listener list instead of
/// just a single listener and its listeners run unconditionally, they
/// do not require a gating boolean return value.
class ScrollNotificationObserverState extends State<ScrollNotificationObserver> {
  LinkedList<_ListenerEntry>? _listeners = LinkedList<_ListenerEntry>();

  bool _debugAssertNotDisposed() {
    assert(() {
      if (_listeners == null) {
        throw FlutterError(
          'A $runtimeType was used after being disposed.\n'
          'Once you have called dispose() on a $runtimeType, it can no longer be used.',
        );
      }
      return true;
    }());
    return true;
  }

  /// Add a [ScrollNotificationCallback] that will be called each time
  /// a descendant scrolls.
  void addListener(ScrollNotificationCallback listener) {
    assert(_debugAssertNotDisposed());
    _listeners!.add(_ListenerEntry(listener));
  }

  /// Remove the specified [ScrollNotificationCallback].
  void removeListener(ScrollNotificationCallback listener) {
    assert(_debugAssertNotDisposed());
    for (final _ListenerEntry entry in _listeners!) {
      if (entry.listener == listener) {
        entry.unlink();
        return;
      }
    }
  }

  void _notifyListeners(ScrollNotification notification) {
    assert(_debugAssertNotDisposed());
    if (_listeners!.isEmpty) {
      return;
    }

    final List<_ListenerEntry> localListeners = List<_ListenerEntry>.of(_listeners!);
    for (final _ListenerEntry entry in localListeners) {
      try {
        if (entry.list != null) {
          entry.listener(notification);
        }
      } catch (exception, stack) {
        FlutterError.reportError(FlutterErrorDetails(
          exception: exception,
          stack: stack,
          library: 'widget library',
          context: ErrorDescription('while dispatching notifications for $runtimeType'),
          informationCollector: () => <DiagnosticsNode>[
            DiagnosticsProperty<ScrollNotificationObserverState>(
              'The $runtimeType sending notification was',
              this,
              style: DiagnosticsTreeStyle.errorProperty,
            ),
          ],
        ));
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    // A ScrollMetricsNotification allows listeners to be notified for an
    // initial state, as well as if the content dimensions change without
    // scrolling.
    return NotificationListener<ScrollMetricsNotification>(
      onNotification: (ScrollMetricsNotification notification) {
        _notifyListeners(_ConvertedScrollMetricsNotification(
          metrics: notification.metrics,
          context: notification.context,
          depth: notification.depth,
        ));
        return false;
      },
      child: NotificationListener<ScrollNotification>(
        onNotification: (ScrollNotification notification) {
          _notifyListeners(notification);
          return false;
        },
        child: _ScrollNotificationObserverScope(
          scrollNotificationObserverState: this,
          child: widget.child,
        ),
      ),
    );
  }

  @override
  void dispose() {
    assert(_debugAssertNotDisposed());
    _listeners = null;
    super.dispose();
  }
}

class _ConvertedScrollMetricsNotification extends ScrollUpdateNotification {
  _ConvertedScrollMetricsNotification({
    required super.metrics,
    required super.context,
    required super.depth,
  });
}
