// 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.

// This test is a use case of flutter/flutter#60796
// the test should be run as:
// flutter drive -t test/using_array.dart --driver test_driver/scrolling_test_e2e_test.dart

import 'dart:ui' as ui;

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:e2e/e2e.dart';

import 'package:complex_layout/main.dart' as app;

class PointerDataTestBinding extends E2EWidgetsFlutterBinding {
  // PointerData injection would usually be considered device input and therefore
  // blocked by [TestWidgetsFlutterBinding]. Override this behavior
  // to help events go into widget tree.
  @override
  void dispatchEvent(
    PointerEvent event,
    HitTestResult hitTestResult, {
    TestBindingEventSource source = TestBindingEventSource.device,
  }) {
    super.dispatchEvent(event, hitTestResult, source: TestBindingEventSource.test);
  }
}

/// A union of [ui.PointerDataPacket] and the time it should be sent.
class PointerDataRecord {
  PointerDataRecord(this.timeStamp, List<ui.PointerData> data)
    : data = ui.PointerDataPacket(data: data);
  final ui.PointerDataPacket data;
  final Duration timeStamp;
}

/// Generates the [PointerDataRecord] to simulate a drag operation from
/// `center - totalMove/2` to `center + totalMove/2`.
Iterable<PointerDataRecord> dragInputDatas(
  final Duration epoch,
  final Offset center, {
  final Offset totalMove = const Offset(0, -400),
  final Duration totalTime = const Duration(milliseconds: 2000),
  final double frequency = 90,
}) sync* {
  final Offset startLocation = (center - totalMove / 2) * ui.window.devicePixelRatio;
  // The issue is about 120Hz input on 90Hz refresh rate device.
  // We test 90Hz input on 60Hz device here, which shows similar pattern.
  final int moveEventCount = totalTime.inMicroseconds * frequency ~/ const Duration(seconds: 1).inMicroseconds;
  final Offset movePerEvent = totalMove / moveEventCount.toDouble() * ui.window.devicePixelRatio;
  yield PointerDataRecord(epoch, <ui.PointerData>[
    ui.PointerData(
      timeStamp: epoch,
      change: ui.PointerChange.add,
      physicalX: startLocation.dx,
      physicalY: startLocation.dy,
    ),
    ui.PointerData(
      timeStamp: epoch,
      change: ui.PointerChange.down,
      physicalX: startLocation.dx,
      physicalY: startLocation.dy,
      pointerIdentifier: 1,
    ),
  ]);
  for (int t = 0; t < moveEventCount + 1; t++) {
    final Offset position = startLocation + movePerEvent * t.toDouble();
    yield PointerDataRecord(
      epoch + totalTime * t ~/ moveEventCount,
      <ui.PointerData>[ui.PointerData(
        timeStamp: epoch + totalTime * t ~/ moveEventCount,
        change: ui.PointerChange.move,
        physicalX: position.dx,
        physicalY: position.dy,
        // Scrolling behavior depends on this delta rather
        // than the position difference.
        physicalDeltaX: movePerEvent.dx,
        physicalDeltaY: movePerEvent.dy,
        pointerIdentifier: 1,
      )],
    );
  }
  final Offset position = startLocation + totalMove;
  yield PointerDataRecord(epoch + totalTime, <ui.PointerData>[ui.PointerData(
    timeStamp: epoch + totalTime,
    change: ui.PointerChange.up,
    physicalX: position.dx,
    physicalY: position.dy,
    pointerIdentifier: 1,
  )]);
}

enum TestScenario {
  resampleOn90Hz,
  resampleOn59Hz,
  resampleOff90Hz,
  resampleOff59Hz,
}

class ResampleFlagVariant extends TestVariant<TestScenario> {
  ResampleFlagVariant(this.binding);
  final E2EWidgetsFlutterBinding binding;

  @override
  final Set<TestScenario> values = Set<TestScenario>.from(TestScenario.values);

  TestScenario currentValue;
  bool get resample {
    switch(currentValue) {
      case TestScenario.resampleOn90Hz:
      case TestScenario.resampleOn59Hz:
        return true;
      case TestScenario.resampleOff90Hz:
      case TestScenario.resampleOff59Hz:
        return false;
    }
    throw ArgumentError;
  }
  double get frequency {
    switch(currentValue) {
      case TestScenario.resampleOn90Hz:
      case TestScenario.resampleOff90Hz:
        return 90.0;
      case TestScenario.resampleOn59Hz:
      case TestScenario.resampleOff59Hz:
        return 59.0;
    }
    throw ArgumentError;
  }

  Map<String, dynamic> result;

  @override
  String describeValue(TestScenario value) {
    switch(value) {
      case TestScenario.resampleOn90Hz:
        return 'resample on with 90Hz input';
      case TestScenario.resampleOn59Hz:
        return 'resample on with 59Hz input';
      case TestScenario.resampleOff90Hz:
        return 'resample off with 90Hz input';
      case TestScenario.resampleOff59Hz:
        return 'resample off with 59Hz input';
    }
    throw ArgumentError;
  }

  @override
  Future<bool> setUp(TestScenario value) async {
    currentValue = value;
    final bool original = binding.resamplingEnabled;
    binding.resamplingEnabled = resample;
    return original;
  }

  @override
  Future<void> tearDown(TestScenario value, bool memento) async {
    binding.resamplingEnabled = memento;
    binding.reportData[describeValue(value)] = result;
  }
}

Future<void> main() async {
  final PointerDataTestBinding binding = PointerDataTestBinding();
  assert(WidgetsBinding.instance == binding);
  binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive;
  binding.reportData ??= <String, dynamic>{};
  final ResampleFlagVariant variant = ResampleFlagVariant(binding);
  testWidgets('Smoothness test', (WidgetTester tester) async {
    app.main();
    await tester.pumpAndSettle();
    final Finder scrollerFinder = find.byKey(const ValueKey<String>('complex-scroll'));
    final ListView scroller = tester.widget<ListView>(scrollerFinder);
    final ScrollController controller = scroller.controller;
    final List<int> frameTimestamp = <int>[];
    final List<double> scrollOffset = <double>[];
    final List<Duration> delays = <Duration>[];
    binding.addPersistentFrameCallback((Duration timeStamp) {
      if (controller.hasClients) {
        // This if is necessary because by the end of the test the widget tree
        // is destroyed.
        frameTimestamp.add(timeStamp.inMicroseconds);
        scrollOffset.add(controller.offset);
      }
    });

    Duration now() => binding.currentSystemFrameTimeStamp;
    Future<void> scroll() async {
      // Extra 50ms to avoid timeouts.
      final Duration startTime = const Duration(milliseconds: 500) + now();
      for (final PointerDataRecord record in dragInputDatas(
        startTime,
        tester.getCenter(scrollerFinder),
        frequency: variant.frequency,
      )) {
        await tester.binding.delayed(record.timeStamp - now());
        // This now measures how accurate the above delayed is.
        final Duration delay = now() - record.timeStamp;
        if (delays.length < frameTimestamp.length) {
          while (delays.length < frameTimestamp.length - 1) {
            delays.add(Duration.zero);
          }
          delays.add(delay);
        } else if (delays.last < delay) {
          delays.last = delay;
        }
        ui.window.onPointerDataPacket(record.data);
      }
    }

    for (int n = 0; n < 5; n++) {
      await scroll();
    }
    variant.result = scrollSummary(scrollOffset, delays, frameTimestamp);
    await tester.pumpAndSettle();
    scrollOffset.clear();
    delays.clear();
    await tester.idle();
  }, semanticsEnabled: false, variant: variant);
}

/// Calculates the smoothness measure from `scrollOffset` and `delays` list.
///
/// Smoothness (`abs_jerk`) is measured by  the absolute value of the discrete
/// 2nd derivative of the scroll offset.
///
/// It was experimented that jerk (3rd derivative of the position) is a good
/// measure the smoothness.
/// Here we are using 2nd derivative instead because the input is completely
/// linear and the expected acceleration should be strictly zero.
/// Observed acceleration is jumping from positive to negative within
/// adjacent frames, meaning mathematically the discrete 3-rd derivative
/// (`f[3] - 3*f[2] + 3*f[1] - f[0]`) is not a good approximation of jerk
/// (continuous 3-rd derivative), while discrete 2nd
/// derivative (`f[2] - 2*f[1] + f[0]`) on the other hand is a better measure
/// of how the scrolling deviate away from linear, and given the acceleration
/// should average to zero within two frames, it's also a good approximation
/// for jerk in terms of physics.
/// We use abs rather than square because square (2-norm) amplifies the
/// effect of the data point that's relatively large, but in this metric
/// we prefer smaller data point to have similar effect.
/// This is also why we count the number of data that's larger than a
/// threshold (and the result is tested not sensitive to this threshold),
/// which is effectively a 0-norm.
///
/// Frames that are too slow to build (longer than 40ms) or with input delay
/// longer than 16ms (1/60Hz) is filtered out to separate the janky due to slow
/// response.
///
/// The returned map has keys:
/// `average_abs_jerk`: average for the overall smoothness.
/// `janky_count`: number of frames with `abs_jerk` larger than 0.5.
/// `dropped_frame_count`: number of frames that are built longer than 40ms and
///  are not used for smoothness measurement.
/// `frame_timestamp`: the list of the timestamp for each frame, in the time
/// order.
/// `scroll_offset`: the scroll offset for each frame. Its length is the same as
/// `frame_timestamp`.
/// `input_delay`: the list of maximum delay time of the input simulation during
/// a frame. Its length is the same as `frame_timestamp`
Map<String, dynamic> scrollSummary(
  List<double> scrollOffset,
  List<Duration> delays,
  List<int> frameTimestamp,
) {
  double jankyCount = 0;
  double absJerkAvg = 0;
  int lostFrame = 0;
  for (int i = 1; i < scrollOffset.length-1; i += 1) {
    if (frameTimestamp[i+1] - frameTimestamp[i-1] > 40E3 ||
        (i >= delays.length || delays[i] > const Duration(milliseconds: 16))) {
      // filter data points from slow frame building or input simulation artifact
      lostFrame += 1;
      continue;
    }
    //
    final double absJerk = (scrollOffset[i-1] + scrollOffset[i+1] - 2*scrollOffset[i]).abs();
    absJerkAvg += absJerk;
    if (absJerk > 0.5)
      jankyCount += 1;
  }
  // expect(lostFrame < 0.1 * frameTimestamp.length, true);
  absJerkAvg /= frameTimestamp.length - lostFrame;

  return <String, dynamic>{
    'janky_count': jankyCount,
    'average_abs_jerk': absJerkAvg,
    'dropped_frame_count': lostFrame,
    'frame_timestamp': List<int>.from(frameTimestamp),
    'scroll_offset': List<double>.from(scrollOffset),
    'input_delay': delays.map<int>((Duration data) => data.inMicroseconds).toList(),
  };
}
