// 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 'dart:ui' show PointerChange;

import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import 'mouse_tracker_test_utils.dart';

typedef MethodCallHandler = Future<dynamic> Function(MethodCall call);
typedef SimpleAnnotationFinder = Iterable<HitTestTarget> Function(Offset offset);

void main() {
  final TestMouseTrackerFlutterBinding binding = TestMouseTrackerFlutterBinding();
  MethodCallHandler? methodCallHandler;

  // Only one of `logCursors` and `cursorHandler` should be specified.
  void setUpMouseTracker({
    required SimpleAnnotationFinder annotationFinder,
    List<_CursorUpdateDetails>? logCursors,
    MethodCallHandler? cursorHandler,
  }) {
    assert(logCursors == null || cursorHandler == null);
    methodCallHandler = logCursors != null
      ? (MethodCall call) async {
        logCursors.add(_CursorUpdateDetails.wrap(call));
        return;
      }
      : cursorHandler;

    binding.setHitTest((BoxHitTestResult result, Offset position) {
      for (final HitTestTarget target in annotationFinder(position)) {
        result.addWithRawTransform(
          transform: Matrix4.identity(),
          position: position,
          hitTest: (BoxHitTestResult result, Offset position) {
            result.add(HitTestEntry(target));
            return true;
          },
        );
      }
      return true;
    });
  }

  void dispatchRemoveDevice([int device = 0]) {
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, Offset.zero, device: device),
    ]));
  }

  setUp(() {
    binding.postFrameCallbacks.clear();
    binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, (MethodCall call) async {
      if (methodCallHandler != null) {
        return methodCallHandler!(call);
      }
      return null;
    });
  });

  tearDown(() {
    binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, null);
  });

  test('Should work on platforms that does not support mouse cursor', () async {
    const TestAnnotationTarget annotation = TestAnnotationTarget(cursor: SystemMouseCursors.grabbing);

    setUpMouseTracker(
      annotationFinder: (Offset position) => <TestAnnotationTarget>[annotation],
      cursorHandler: (MethodCall call) async {
        return null;
      },
    );

    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));
    addTearDown(dispatchRemoveDevice);

    // Passes if no errors are thrown
  });

  test('pointer is added and removed out of any annotations', () {
    final List<_CursorUpdateDetails> logCursors = <_CursorUpdateDetails>[];
    TestAnnotationTarget? annotation;
    setUpMouseTracker(
      annotationFinder: (Offset position) => <TestAnnotationTarget>[if (annotation != null) annotation],
      logCursors: logCursors,
    );

    // Pointer is added outside of the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.basic.kind),
    ]);
    logCursors.clear();

    // Pointer moves into the annotation
    annotation = const TestAnnotationTarget(cursor: SystemMouseCursors.grabbing);
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(5.0, 0.0)),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.grabbing.kind),
    ]);
    logCursors.clear();

    // Pointer moves within the annotation
    annotation = const TestAnnotationTarget(cursor: SystemMouseCursors.grabbing);
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(10.0, 0.0)),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[]);
    logCursors.clear();

    // Pointer moves out of the annotation
    annotation = null;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.basic.kind),
    ]);
    logCursors.clear();

    // Pointer is removed outside of the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, Offset.zero),
    ]));

    expect(logCursors, const <_CursorUpdateDetails>[]);
  });

  test('pointer is added and removed in an annotation', () {
    final List<_CursorUpdateDetails> logCursors = <_CursorUpdateDetails>[];
    TestAnnotationTarget? annotation;
    setUpMouseTracker(
      annotationFinder: (Offset position) => <TestAnnotationTarget>[if (annotation != null) annotation],
      logCursors: logCursors,
    );

    // Pointer is added in the annotation.
    annotation = const TestAnnotationTarget(cursor: SystemMouseCursors.grabbing);
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.grabbing.kind),
    ]);
    logCursors.clear();

    // Pointer moves out of the annotation
    annotation = null;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(5.0, 0.0)),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.basic.kind),
    ]);
    logCursors.clear();

    // Pointer moves around out of the annotation
    annotation = null;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(10.0, 0.0)),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[]);
    logCursors.clear();

    // Pointer moves back into the annotation
    annotation = const TestAnnotationTarget(cursor: SystemMouseCursors.grabbing);
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.grabbing.kind),
    ]);
    logCursors.clear();

    // Pointer is removed within the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[]);
  });

  test('pointer change caused by new frames', () {
    final List<_CursorUpdateDetails> logCursors = <_CursorUpdateDetails>[];
    TestAnnotationTarget? annotation;
    setUpMouseTracker(
      annotationFinder: (Offset position) => <TestAnnotationTarget>[if (annotation != null) annotation],
      logCursors: logCursors,
    );

    // Pointer is added outside of the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.basic.kind),
    ]);
    logCursors.clear();

    // Synthesize a new frame while changing annotation
    annotation = const TestAnnotationTarget(cursor: SystemMouseCursors.grabbing);
    binding.scheduleMouseTrackerPostFrameCheck();
    binding.flushPostFrameCallbacks(Duration.zero);

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.grabbing.kind),
    ]);
    logCursors.clear();

    // Synthesize a new frame without changing annotation
    annotation = const TestAnnotationTarget(cursor: SystemMouseCursors.grabbing);
    binding.scheduleMouseTrackerPostFrameCheck();

    expect(logCursors, <_CursorUpdateDetails>[]);
    logCursors.clear();

    // Pointer is removed outside of the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[]);
  });

  test('The first annotation with non-deferring cursor is used', () {
    final List<_CursorUpdateDetails> logCursors = <_CursorUpdateDetails>[];
    late List<TestAnnotationTarget> annotations;
    setUpMouseTracker(
      annotationFinder: (Offset position) sync* { yield* annotations; },
      logCursors: logCursors,
    );

    annotations = <TestAnnotationTarget>[
      const TestAnnotationTarget(),
      const TestAnnotationTarget(cursor: SystemMouseCursors.click),
      const TestAnnotationTarget(cursor: SystemMouseCursors.grabbing),
    ];
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.click.kind),
    ]);
    logCursors.clear();

    // Remove
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, const Offset(5.0, 0.0)),
    ]));
  });

  test('Annotations with deferring cursors are ignored', () {
    final List<_CursorUpdateDetails> logCursors = <_CursorUpdateDetails>[];
    late List<TestAnnotationTarget> annotations;
    setUpMouseTracker(
      annotationFinder: (Offset position) sync* { yield* annotations; },
      logCursors: logCursors,
    );

    annotations = <TestAnnotationTarget>[
      const TestAnnotationTarget(),
      const TestAnnotationTarget(),
      const TestAnnotationTarget(cursor: SystemMouseCursors.grabbing),
    ];
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.grabbing.kind),
    ]);
    logCursors.clear();

    // Remove
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, const Offset(5.0, 0.0)),
    ]));
  });

  test('Finding no annotation is equivalent to specifying default cursor', () {
    final List<_CursorUpdateDetails> logCursors = <_CursorUpdateDetails>[];
    TestAnnotationTarget? annotation;
    setUpMouseTracker(
      annotationFinder: (Offset position) => <TestAnnotationTarget>[if (annotation != null) annotation],
      logCursors: logCursors,
    );

    // Pointer is added outside of the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.basic.kind),
    ]);
    logCursors.clear();

    // Pointer moved to an annotation specified with the default cursor
    annotation = const TestAnnotationTarget(cursor: SystemMouseCursors.basic);
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(5.0, 0.0)),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[]);
    logCursors.clear();

    // Pointer moved to no annotations
    annotation = null;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, Offset.zero),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[]);
    logCursors.clear();

    // Remove
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, Offset.zero),
    ]));
  });

  test('Removing a pointer resets it back to the default cursor', () {
    final List<_CursorUpdateDetails> logCursors = <_CursorUpdateDetails>[];
    TestAnnotationTarget? annotation;
    setUpMouseTracker(
      annotationFinder: (Offset position) => <TestAnnotationTarget>[if (annotation != null) annotation],
      logCursors: logCursors,
    );

    // Pointer is added to the annotation, then removed
    annotation = const TestAnnotationTarget(cursor: SystemMouseCursors.click);
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
      _pointerData(PointerChange.hover, const Offset(5.0, 0.0)),
      _pointerData(PointerChange.remove, const Offset(5.0, 0.0)),
    ]));

    logCursors.clear();

    // Pointer is added out of the annotation
    annotation = null;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));
    addTearDown(dispatchRemoveDevice);

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 0, kind: SystemMouseCursors.basic.kind),
    ]);
    logCursors.clear();
  });

  test('Pointing devices display cursors separately', () {
    final List<_CursorUpdateDetails> logCursors = <_CursorUpdateDetails>[];
    setUpMouseTracker(
      annotationFinder: (Offset position) sync* {
        if (position.dx > 200) {
          yield const TestAnnotationTarget(cursor: SystemMouseCursors.forbidden);
        } else if (position.dx > 100) {
          yield const TestAnnotationTarget(cursor: SystemMouseCursors.click);
        } else {}
      },
      logCursors: logCursors,
    );

    // Pointers are added outside of the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero, device: 1),
      _pointerData(PointerChange.add, Offset.zero, device: 2),
    ]));
    addTearDown(() => dispatchRemoveDevice(1));
    addTearDown(() => dispatchRemoveDevice(2));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 1, kind: SystemMouseCursors.basic.kind),
      _CursorUpdateDetails.activateSystemCursor(device: 2, kind: SystemMouseCursors.basic.kind),
    ]);
    logCursors.clear();

    // Pointer 1 moved to cursor "click"
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(101.0, 0.0), device: 1),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 1, kind: SystemMouseCursors.click.kind),
    ]);
    logCursors.clear();

    // Pointer 2 moved to cursor "click"
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(102.0, 0.0), device: 2),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 2, kind: SystemMouseCursors.click.kind),
    ]);
    logCursors.clear();

    // Pointer 2 moved to cursor "forbidden"
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(202.0, 0.0), device: 2),
    ]));

    expect(logCursors, <_CursorUpdateDetails>[
      _CursorUpdateDetails.activateSystemCursor(device: 2, kind: SystemMouseCursors.forbidden.kind),
    ]);
    logCursors.clear();
  });
}

ui.PointerData _pointerData(
  PointerChange change,
  Offset logicalPosition, {
  int device = 0,
  PointerDeviceKind kind = PointerDeviceKind.mouse,
}) {
  return ui.PointerData(
    change: change,
    physicalX: logicalPosition.dx * RendererBinding.instance.window.devicePixelRatio,
    physicalY: logicalPosition.dy * RendererBinding.instance.window.devicePixelRatio,
    kind: kind,
    device: device,
  );
}

class _CursorUpdateDetails extends MethodCall {
  const _CursorUpdateDetails(super.method, Map<String, dynamic> super.arguments)
    : assert(arguments != null);

  _CursorUpdateDetails.wrap(MethodCall call)
    : super(call.method, Map<String, dynamic>.from(call.arguments as Map<dynamic, dynamic>));

  _CursorUpdateDetails.activateSystemCursor({
    required int device,
    required String kind,
  }) : this('activateSystemCursor', <String, dynamic>{'device': device, 'kind': kind});
  @override
  Map<String, dynamic> get arguments => super.arguments as Map<String, dynamic>;

  @override
  bool operator ==(dynamic other) {
    if (identical(other, this)) {
      return true;
    }
    if (other.runtimeType != runtimeType) {
      return false;
    }
    return other is _CursorUpdateDetails
        && other.method == method
        && other.arguments.length == arguments.length
        && other.arguments.entries.every(
          (MapEntry<String, dynamic> entry) =>
            arguments.containsKey(entry.key) && arguments[entry.key] == entry.value,
        );
  }

  @override
  int get hashCode => Object.hash(method, arguments);

  @override
  String toString() {
    return '_CursorUpdateDetails(method: $method, arguments: $arguments)';
  }
}
