// 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:ui' as ui;

import 'package:clock/clock.dart';
import 'package:fake_async/fake_async.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_test/flutter_test.dart';

typedef HandleEventCallback = void Function(PointerEvent event);

class TestResampleEventFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding {
  HandleEventCallback? callback;
  FrameCallback? postFrameCallback;
  Duration? frameTime;

  @override
  void handleEvent(PointerEvent event, HitTestEntry entry) {
    super.handleEvent(event, entry);
    if (callback != null)
      callback?.call(event);
  }

  @override
  Duration get currentSystemFrameTimeStamp {
    assert(frameTime != null);
    return frameTime!;
  }

  @override
  int addPostFrameCallback(FrameCallback callback) {
    postFrameCallback = callback;
    return 0;
  }

  @override
  SamplingClock? get debugSamplingClock => TestSamplingClock();
}

class TestSamplingClock implements SamplingClock {
  @override
  DateTime now() => clock.now();

  @override
  Stopwatch stopwatch() => clock.stopwatch();
}

typedef ResampleEventTest = void Function(FakeAsync async);

void testResampleEvent(String description, ResampleEventTest callback) {
  test(description, () {
    fakeAsync((FakeAsync async) {
      callback(async);
    }, initialTime: DateTime.utc(2015));
  }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87067
                       // Fake clock is not working with the web platform.
}

void main() {
  final TestResampleEventFlutterBinding binding = TestResampleEventFlutterBinding();
  testResampleEvent('Pointer event resampling', (FakeAsync async) {
    Duration currentTime() => Duration(milliseconds: clock.now().millisecondsSinceEpoch);
    final Duration epoch = currentTime();
    final ui.PointerDataPacket packet = ui.PointerDataPacket(
      data: <ui.PointerData>[
        ui.PointerData(
            change: ui.PointerChange.add,
            timeStamp: epoch,
        ),
        ui.PointerData(
            change: ui.PointerChange.down,
            timeStamp: epoch + const Duration(milliseconds: 10),
        ),
        ui.PointerData(
            change: ui.PointerChange.move,
            physicalX: 10.0,
            timeStamp: epoch + const Duration(milliseconds: 20),
        ),
        ui.PointerData(
            change: ui.PointerChange.move,
            physicalX: 20.0,
            timeStamp: epoch + const Duration(milliseconds: 30),
        ),
        ui.PointerData(
            change: ui.PointerChange.move,
            physicalX: 30.0,
            timeStamp: epoch + const Duration(milliseconds: 40),
        ),
        ui.PointerData(
            change: ui.PointerChange.move,
            physicalX: 40.0,
            timeStamp: epoch + const Duration(milliseconds: 50),
        ),
        ui.PointerData(
            change: ui.PointerChange.move,
            physicalX: 50.0,
            timeStamp: epoch + const Duration(milliseconds: 60),
        ),
        ui.PointerData(
            change: ui.PointerChange.up,
            physicalX: 50.0,
            timeStamp: epoch + const Duration(milliseconds: 70),
        ),
        ui.PointerData(
            change: ui.PointerChange.remove,
            physicalX: 50.0,
            timeStamp: epoch + const Duration(milliseconds: 70),
        ),
      ],
    );

    const Duration samplingOffset = Duration(milliseconds: -5);
    const Duration frameInterval = Duration(microseconds: 16667);

    GestureBinding.instance!.resamplingEnabled = true;
    GestureBinding.instance!.samplingOffset = samplingOffset;

    final List<PointerEvent> events = <PointerEvent>[];
    binding.callback = events.add;

    ui.window.onPointerDataPacket?.call(packet);

    // No pointer events should have been dispatched yet.
    expect(events.length, 0);

    // Frame callback should have been requested.
    FrameCallback? callback = binding.postFrameCallback;
    binding.postFrameCallback = null;
    expect(callback, isNotNull);

    binding.frameTime = epoch + const Duration(milliseconds: 15);
    callback!(Duration.zero);

    // One pointer event should have been dispatched.
    expect(events.length, 1);
    expect(events[0], isA<PointerDownEvent>());
    expect(events[0].timeStamp, binding.frameTime! + samplingOffset);
    expect(events[0].position, Offset(0.0 / ui.window.devicePixelRatio, 0.0));

    // Second frame callback should have been requested.
    callback = binding.postFrameCallback;
    binding.postFrameCallback = null;
    expect(callback, isNotNull);

    final Duration frameTime = epoch + const Duration(milliseconds: 25);
    binding.frameTime = frameTime;
    callback!(Duration.zero);

    // Second pointer event should have been dispatched.
    expect(events.length, 2);
    expect(events[1], isA<PointerMoveEvent>());
    expect(events[1].timeStamp, binding.frameTime! + samplingOffset);
    expect(events[1].position, Offset(10.0 / ui.window.devicePixelRatio, 0.0));
    expect(events[1].delta, Offset(10.0 / ui.window.devicePixelRatio, 0.0));

    // Verify that resampling continues without a frame callback.
    async.elapse(frameInterval * 1.5);

    // Third pointer event should have been dispatched.
    expect(events.length, 3);
    expect(events[2], isA<PointerMoveEvent>());
    expect(events[2].timeStamp, frameTime + frameInterval + samplingOffset);

    async.elapse(frameInterval);

    // Remaining pointer events should have been dispatched.
    expect(events.length, 5);
    expect(events[3], isA<PointerMoveEvent>());
    expect(events[3].timeStamp, frameTime + frameInterval * 2 + samplingOffset);
    expect(events[4], isA<PointerUpEvent>());
    expect(events[4].timeStamp, frameTime + frameInterval * 2 + samplingOffset);

    async.elapse(frameInterval);

    // No more pointer events should have been dispatched.
    expect(events.length, 5);

    GestureBinding.instance!.resamplingEnabled = false;
  });
}
