// Copyright (c) 2023, 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 'dart:async';
import 'dart:js_interop';

import '../../dom.dart' as html;
import '../../helpers.dart' show Device;

/// Helper class used to create streams abstracting DOM events. This is a
/// piece of the helper layer directly derived from a similar feature in
/// `dart:html`.
///
/// A few differences compared to `dart:html`:
///   * The helper layer doesn't have `ElementList` APIs, so this
///     provider omits APIs related to them.
///
///   * Streams returned here behave slighly differently. The timing of when
///     callbacks execute is sometimes different when using stream to future APIs
///     like `.first`. In particular, when using synchronous browser APIs like
///     `dispatchEvent`, the Dart callbacks that would have executed
///     synchronously in `dart:html`, may now execute asynchronously. This only
///     breaks code that relied on specific timing details of the
///     implementation, but at an API level, the change is non breaking.
class EventStreamProvider<T extends html.Event> {
  final String _eventType;

  const EventStreamProvider(this._eventType);

  /// Gets a [Stream] for this event type, on the specified target.
  ///
  /// This will always return a broadcast stream so multiple listeners can be
  /// used simultaneously.
  ///
  /// This may be used to capture DOM events:
  ///
  ///     Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
  ///
  ///     // Alternate method:
  ///     Element.keyDownEvent.forTarget(element).capture(...);
  ///
  /// Or for listening to an event which will bubble through the DOM tree:
  ///
  ///     MediaElement.pauseEvent.forTarget(document.body).listen(...);
  ///
  /// See also:
  ///
  /// * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
  ///   from MDN.
  Stream<T> forTarget(html.EventTarget? e, {bool useCapture = false}) =>
      _EventStream<T>(e, _eventType, useCapture);

  /// Gets a [Stream] for this event type, on the specified element.
  ///
  /// This will always return a broadcast stream so multiple listeners can be
  /// used simultaneously.
  ///
  /// This may be used to capture DOM events:
  ///
  ///     Element.keyDownEvent.forElement(element, useCapture: true)
  ///       .listen(...);
  ///
  ///     // Alternate method:
  ///     Element.keyDownEvent.forElement(element).capture(...);
  ///
  /// Or for listening to an event which will bubble through the DOM tree:
  ///
  ///     MediaElement.pauseEvent.forElement(document.body).listen(...);
  ///
  /// See also:
  ///
  /// * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
  ///   from MDN.
  ElementStream<T> forElement(html.Element e, {bool useCapture = false}) =>
      _ElementEventStreamImpl<T>(e, _eventType, useCapture);

  /// Gets the type of the event which this would listen for on the specified
  /// event target.
  ///
  /// The target is necessary because some browsers may use different event
  /// names for the same purpose and the target allows differentiating browser
  /// support.
  String getEventType(html.EventTarget target) => _eventType;
}

/// A stream that allows capturing events on a parent element.
///
/// Note, unlike `dart:html`'s `ElementStream`, this implementation doesn't
/// provide the jquery style `matches` filtering functionality.
abstract class ElementStream<T extends html.Event> implements Stream<T> {
  /// Adds a capturing subscription to this stream.
  ///
  /// If the target of the event is a descendant of the element from which this
  /// stream derives then [onData] is called before the event propagates down to
  /// the target. This is the opposite of bubbling behavior, where the event
  /// is first processed for the event target and then bubbles upward.
  ///
  /// ## Other resources
  ///
  /// * [Event Capture](http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture)
  ///   from the W3C DOM Events specification.
  StreamSubscription<T> capture(void Function(T) onData);
}

/// Adapter for exposing DOM events as Dart streams.
class _EventStream<T extends html.Event> extends Stream<T> {
  final html.EventTarget? _target;
  final String _eventType;
  final bool _useCapture;

  _EventStream(this._target, this._eventType, this._useCapture);

  // DOM events are inherently multi-subscribers.
  @override
  Stream<T> asBroadcastStream(
          {void Function(StreamSubscription<T>)? onListen,
          void Function(StreamSubscription<T>)? onCancel}) =>
      this;

  @override
  bool get isBroadcast => true;

  // TODO(9757): Inlining should be smart and inline only when inlining would
  // enable scalar replacement of an immediately allocated receiver.
  @pragma('dart2js:tryInline')
  @override
  StreamSubscription<T> listen(void Function(T)? onData,
          {Function? onError, void Function()? onDone, bool? cancelOnError}) =>
      _EventStreamSubscription<T>(_target, _eventType, onData, _useCapture);
}

/// Adapter for exposing DOM Element events as streams
class _ElementEventStreamImpl<T extends html.Event> extends _EventStream<T>
    implements ElementStream<T> {
  _ElementEventStreamImpl(super.target, super.eventType, super.useCapture);
  @override
  StreamSubscription<T> capture(void Function(T) onData) =>
      _EventStreamSubscription<T>(_target, _eventType, onData, true);
}

class _EventStreamSubscription<T extends html.Event>
    implements StreamSubscription<T> {
  int _pauseCount = 0;
  html.EventTarget? _target;
  final String _eventType;
  html.EventListener? _onData;
  final bool _useCapture;

  // TODO(leafp): It would be better to write this as
  // _onData = onData == null ? null :
  //   onData is void Function(Event)
  //     ? _wrapZone<Event>(onData)
  //     : _wrapZone<Event>((e) => onData(e as T))
  // In order to support existing tests which pass the wrong type of events but
  // use a more general listener, without causing as much slowdown for things
  // which are typed correctly.  But this currently runs afoul of restrictions
  // on is checks for compatibility with the VM.
  _EventStreamSubscription(
      this._target, this._eventType, void Function(T)? onData, this._useCapture)
      : _onData = onData == null
            ? null
            // ignore: avoid_dynamic_calls
            : _wrapZone<html.Event>((e) => (onData as dynamic)(e))?.toJS {
    _tryResume();
  }

  @override
  Future<void> cancel() {
    // Note: the use of `emptyFuture` here has an indirect effect. The timing of
    // when stream listeners get dispatched is different from that of
    // `dart:html`.
    //
    // For example, the following program prints 1, 2, 3, 4, but with
    // `dart:html` it would have printed 1, 2, 4, 3
    //
    // ```dart
    // import 'package:web/web.dart';
    //
    // void main() {
    //   print('1');
    //   final body = document.body!;
    //   body.onTouchStart.first.whenComplete(() {
    //     print('4');
    //   });
    //
    //   print('2');
    //   body.dispatchEvent(TouchEvent('touchstart'));
    //   print('3');
    // }
    // ```
    //
    // More details can be found on [this change][1].
    // [1]: https://dart-review.googlesource.com/c/sdk/+/175323
    final emptyFuture = Future<void>.value();
    if (_canceled) return emptyFuture;

    _unlisten();
    // Clear out the target to indicate this is complete.
    _target = null;
    _onData = null;
    return emptyFuture;
  }

  bool get _canceled => _target == null;

  @override
  void onData(void Function(T)? handleData) {
    if (_canceled) {
      throw StateError('Subscription has been canceled.');
    }
    // Remove current event listener.
    _unlisten();
    _onData = handleData == null
        ? null
        // ignore: avoid_dynamic_calls
        : _wrapZone<html.Event>((e) => (handleData as dynamic)(e))?.toJS;
    _tryResume();
  }

  /// Has no effect.
  @override
  void onError(Function? handleError) {}

  /// Has no effect.
  @override
  void onDone(void Function()? handleDone) {}

  @override
  void pause([Future<dynamic>? resumeSignal]) {
    if (_canceled) return;
    ++_pauseCount;
    _unlisten();

    if (resumeSignal != null) {
      resumeSignal.whenComplete(resume);
    }
  }

  @override
  bool get isPaused => _pauseCount > 0;

  @override
  void resume() {
    if (_canceled || !isPaused) return;
    --_pauseCount;
    _tryResume();
  }

  void _tryResume() {
    if (_onData != null && !isPaused) {
      _target!.addEventListener(_eventType, _onData, _useCapture.toJS);
    }
  }

  void _unlisten() {
    if (_onData != null) {
      _target!.removeEventListener(_eventType, _onData, _useCapture.toJS);
    }
  }

  @override
  Future<E> asFuture<E>([E? futureValue]) =>
      // We just need a future that will never succeed or fail.
      Completer<E>().future;
}

/// Base class that supports listening for and dispatching browser events.
///
/// Normally events are accessed via the Stream getter:
///
///     element.onMouseOver.listen((e) => print('Mouse over!'));
///
/// To access bubbling events which are declared on one element, but may bubble
/// up to another element type (common for MediaElement events):
///
///     MediaElement.pauseEvent.forTarget(document.body).listen(...);
///
/// To useCapture on events:
///
///     Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
///
/// Custom events can be declared as:
///
///     class DataGenerator {
///       static EventStreamProvider<Event> dataEvent =
///           new EventStreamProvider('data');
///     }
///
/// Then listeners should access the event with:
///
///     DataGenerator.dataEvent.forTarget(element).listen(...);
///
/// Custom events can also be accessed as:
///
///     element.on['some_event'].listen(...);
///
/// This approach is generally discouraged as it loses the event typing and
/// some DOM events may have multiple platform-dependent event names under the
/// covers. By using the standard Stream getters you will get the platform
/// specific event name automatically.
class Events {
  final html.EventTarget _ptr;

  Events(this._ptr);

  Stream<html.Event> operator [](String type) =>
      _EventStream(_ptr, type, false);
}

class ElementEvents extends Events {
  static final _webkitEvents = {
    'animationend': 'webkitAnimationEnd',
    'animationiteration': 'webkitAnimationIteration',
    'animationstart': 'webkitAnimationStart',
    'fullscreenchange': 'webkitfullscreenchange',
    'fullscreenerror': 'webkitfullscreenerror',
    'keyadded': 'webkitkeyadded',
    'keyerror': 'webkitkeyerror',
    'keymessage': 'webkitkeymessage',
    'needkey': 'webkitneedkey',
    'pointerlockchange': 'webkitpointerlockchange',
    'pointerlockerror': 'webkitpointerlockerror',
    'resourcetimingbufferfull': 'webkitresourcetimingbufferfull',
    'transitionend': 'webkitTransitionEnd',
    'speechchange': 'webkitSpeechChange'
  };

  ElementEvents(html.Element super.ptr);

  @override
  Stream<html.Event> operator [](String type) {
    if (_webkitEvents.keys.contains(type.toLowerCase())) {
      if (Device.isWebKit) {
        return _ElementEventStreamImpl(
            _ptr, _webkitEvents[type.toLowerCase()]!, false);
      }
    }
    return _ElementEventStreamImpl(_ptr, type, false);
  }
}

/// Helper class to implement custom events which wrap DOM events.
// TODO(b/261997228): Add support for CustomEvents now that WrappedEvent is not
// implementing the JS interop html.Event type.
class WrappedEvent {
  final html.Event wrapped;

  /// The CSS selector involved with event delegation.
  String? _selector;

  WrappedEvent(this.wrapped);

  bool get bubbles => wrapped.bubbles;

  bool get cancelable => wrapped.cancelable;

  bool get composed => wrapped.composed;

  html.EventTarget? get currentTarget => wrapped.currentTarget;

  bool get defaultPrevented => wrapped.defaultPrevented;

  int get eventPhase => wrapped.eventPhase;

  bool get isTrusted => wrapped.isTrusted;

  html.EventTarget? get target => wrapped.target;

  double get timeStamp => wrapped.timeStamp.toDouble();

  String get type => wrapped.type;

  void preventDefault() {
    wrapped.preventDefault();
  }

  void stopImmediatePropagation() {
    wrapped.stopImmediatePropagation();
  }

  void stopPropagation() {
    wrapped.stopPropagation();
  }

  List<html.EventTarget> composedPath() =>
      wrapped.composedPath().toDart.cast<html.EventTarget>();

  html.Element get matchingTarget {
    if (_selector == null) {
      throw UnsupportedError('Cannot call matchingTarget if this Event did'
          ' not arise as a result of event delegation.');
    }
    final currentTarget = this.currentTarget as html.Element?;
    var target = this.target as html.Element?;
    do {
      if (target!.matches(_selector!)) return target;
      target = target.parentElement;
    } while (target != null && target != currentTarget!.parentElement);
    throw StateError('No selector matched for populating matchedTarget.');
  }
}

void Function(T)? _wrapZone<T>(void Function(T)? callback) {
  // For performance reasons avoid wrapping if we are in the root zone.
  if (Zone.current == Zone.root) return callback;
  if (callback == null) return null;
  return Zone.current.bindUnaryCallbackGuarded(callback);
}

void Function(T1, T2)? wrapBinaryZone<T1, T2>(void Function(T1, T2)? callback) {
  // For performance reasons avoid wrapping if we are in the root zone.
  if (Zone.current == Zone.root) return callback;
  if (callback == null) return null;
  return Zone.current.bindBinaryCallbackGuarded(callback);
}

/// A stream of custom events, which enables the user to "fire" (add) their own
/// custom events to a stream.
abstract class CustomStream<T extends html.Event> implements Stream<T> {
  /// Add the following custom event to the stream for dispatching to interested
  /// listeners.
  void add(T event);
}

class CustomEventStreamImpl<T extends html.Event> extends Stream<T>
    implements CustomStream<T> {
  StreamController<T> streamController;

  /// The type of event this stream is providing (e.g. "keydown").
  String type;

  CustomEventStreamImpl(this.type)
      : streamController = StreamController.broadcast(sync: true);

  // Delegate all regular Stream behavior to our wrapped Stream.
  @override
  StreamSubscription<T> listen(void Function(T)? onData,
          {Function? onError, void Function()? onDone, bool? cancelOnError}) =>
      streamController.stream.listen(onData,
          onError: onError, onDone: onDone, cancelOnError: cancelOnError);

  @override
  Stream<T> asBroadcastStream(
          {void Function(StreamSubscription<T>)? onListen,
          void Function(StreamSubscription<T>)? onCancel}) =>
      streamController.stream;

  @override
  bool get isBroadcast => true;

  @override
  void add(T event) {
    if (event.type == type) streamController.add(event);
  }
}

/// A factory to expose DOM events as streams, where the DOM event name has to
/// be determined on the fly (for example, mouse wheel events).
class CustomEventStreamProvider<T extends html.Event>
    implements EventStreamProvider<T> {
  final String Function(html.EventTarget) _eventTypeGetter;
  const CustomEventStreamProvider(this._eventTypeGetter);

  @override
  Stream<T> forTarget(html.EventTarget? e, {bool useCapture = false}) =>
      _EventStream<T>(e, _eventTypeGetter(e!), useCapture);

  @override
  ElementStream<T> forElement(html.Element e, {bool useCapture = false}) =>
      _ElementEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);

  @override
  String getEventType(html.EventTarget target) => _eventTypeGetter(target);

  @override
  String get _eventType =>
      throw UnsupportedError('Access type through getEventType method.');
}
