// 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 handlePointerEvent(
    PointerEvent event, {
    TestBindingEventSource source = TestBindingEventSource.device,
  }) {
    super.handlePointerEvent(event, 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(),
  };
}
