// 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 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

late GestureVelocityTrackerBuilder lastCreatedBuilder;
class TestScrollBehavior extends ScrollBehavior {
  const TestScrollBehavior(this.flag);

  final bool flag;

  @override
  ScrollPhysics getScrollPhysics(BuildContext context) {
    return flag
      ? const ClampingScrollPhysics()
      : const BouncingScrollPhysics();
  }

  @override
  bool shouldNotify(TestScrollBehavior old) => flag != old.flag;

  @override
  GestureVelocityTrackerBuilder velocityTrackerBuilder(BuildContext context) {
      lastCreatedBuilder = flag
        ? (PointerEvent ev) => VelocityTracker.withKind(ev.kind)
        : (PointerEvent ev) => IOSScrollViewFlingVelocityTracker(ev.kind);
      return lastCreatedBuilder;
  }
}

void main() {
  // Regression test for https://github.com/flutter/flutter/issues/89681
  testWidgets('_WrappedScrollBehavior shouldNotify test', (WidgetTester tester) async {
    final ScrollBehavior behavior1 = const ScrollBehavior().copyWith();
    final ScrollBehavior behavior2 = const ScrollBehavior().copyWith();

    expect(behavior1.shouldNotify(behavior2), false);
  });

  testWidgets('Inherited ScrollConfiguration changed', (WidgetTester tester) async {
    final GlobalKey key = GlobalKey(debugLabel: 'scrollable');
    TestScrollBehavior? behavior;
    late ScrollPositionWithSingleContext position;

    final Widget scrollView = SingleChildScrollView(
      key: key,
      child: Builder(
        builder: (BuildContext context) {
          behavior = ScrollConfiguration.of(context) as TestScrollBehavior;
          position = Scrollable.of(context)!.position as ScrollPositionWithSingleContext;
          return Container(height: 1000.0);
        },
      ),
    );

    await tester.pumpWidget(
      ScrollConfiguration(
        behavior: const TestScrollBehavior(true),
        child: scrollView,
      ),
    );

    expect(behavior, isNotNull);
    expect(behavior!.flag, isTrue);
    expect(position.physics, isA<ClampingScrollPhysics>());
    expect(lastCreatedBuilder(const PointerDownEvent()), isA<VelocityTracker>());
    ScrollMetrics metrics = position.copyWith();
    expect(metrics.extentAfter, equals(400.0));
    expect(metrics.viewportDimension, equals(600.0));

    // Same Scrollable, different ScrollConfiguration
    await tester.pumpWidget(
      ScrollConfiguration(
        behavior: const TestScrollBehavior(false),
        child: scrollView,
      ),
    );

    expect(behavior, isNotNull);
    expect(behavior!.flag, isFalse);
    expect(position.physics, isA<BouncingScrollPhysics>());
    expect(lastCreatedBuilder(const PointerDownEvent()), isA<IOSScrollViewFlingVelocityTracker>());
    // Regression test for https://github.com/flutter/flutter/issues/5856
    metrics = position.copyWith();
    expect(metrics.extentAfter, equals(400.0));
    expect(metrics.viewportDimension, equals(600.0));
  });

  testWidgets('ScrollBehavior default android overscroll indicator', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: ScrollConfiguration(
          behavior: const ScrollBehavior(),
          child: ListView(
            children: const <Widget>[
              SizedBox(
                height: 1000.0,
                width: 1000.0,
                child: Text('Test'),
              ),
            ],
          ),
        ),
      ),
    );

    expect(find.byType(StretchingOverscrollIndicator), findsNothing);
    expect(find.byType(GlowingOverscrollIndicator), findsOneWidget);
  }, variant: TargetPlatformVariant.only(TargetPlatform.android));

  testWidgets('ScrollBehavior stretch android overscroll indicator', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: MediaQuery(
          data: const MediaQueryData(size: Size(800, 600)),
          child: ScrollConfiguration(
            behavior: const ScrollBehavior(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch),
            child: ListView(
              children: const <Widget>[
                SizedBox(
                  height: 1000.0,
                  width: 1000.0,
                  child: Text('Test'),
                ),
              ],
            ),
          ),
        ),
      ),
    );

    expect(find.byType(StretchingOverscrollIndicator), findsOneWidget);
    expect(find.byType(GlowingOverscrollIndicator), findsNothing);
  }, variant: TargetPlatformVariant.only(TargetPlatform.android));

  group('ScrollBehavior configuration is maintained over multiple copies', () {
    testWidgets('dragDevices', (WidgetTester tester) async {
      // Regression test for https://github.com/flutter/flutter/issues/91673
      const ScrollBehavior defaultBehavior = ScrollBehavior();
      expect(defaultBehavior.dragDevices, <PointerDeviceKind>{
        PointerDeviceKind.touch,
        PointerDeviceKind.stylus,
        PointerDeviceKind.invertedStylus,
        PointerDeviceKind.trackpad,
        PointerDeviceKind.unknown,
      });

      // Use copyWith to modify drag devices
      final ScrollBehavior onceCopiedBehavior = defaultBehavior.copyWith(
        dragDevices: PointerDeviceKind.values.toSet(),
      );
      expect(onceCopiedBehavior.dragDevices, PointerDeviceKind.values.toSet());

      // Copy again. The previously modified drag devices should carry over.
      final ScrollBehavior twiceCopiedBehavior = onceCopiedBehavior.copyWith();
      expect(twiceCopiedBehavior.dragDevices, PointerDeviceKind.values.toSet());
    });

    testWidgets('androidOverscrollIndicator', (WidgetTester tester) async {
      // Regression test for https://github.com/flutter/flutter/issues/91673
      const ScrollBehavior defaultBehavior = ScrollBehavior();
      expect(defaultBehavior.androidOverscrollIndicator, AndroidOverscrollIndicator.glow);

      // Use copyWith to modify androidOverscrollIndicator
      final ScrollBehavior onceCopiedBehavior = defaultBehavior.copyWith(
        androidOverscrollIndicator: AndroidOverscrollIndicator.stretch,
      );
      expect(onceCopiedBehavior.androidOverscrollIndicator, AndroidOverscrollIndicator.stretch);

      // Copy again. The previously modified value should carry over.
      final ScrollBehavior twiceCopiedBehavior = onceCopiedBehavior.copyWith();
      expect(twiceCopiedBehavior.androidOverscrollIndicator, AndroidOverscrollIndicator.stretch);
    });

    testWidgets('physics', (WidgetTester tester) async {
      // Regression test for https://github.com/flutter/flutter/issues/91673
      late ScrollPhysics defaultPhysics;
      late ScrollPhysics onceCopiedPhysics;
      late ScrollPhysics twiceCopiedPhysics;

      await tester.pumpWidget(ScrollConfiguration(
        // Default ScrollBehavior
        behavior: const ScrollBehavior(),
        child: Builder(
          builder: (BuildContext context) {
            final ScrollBehavior defaultBehavior = ScrollConfiguration.of(context);
            // Copy once to change physics
            defaultPhysics = defaultBehavior.getScrollPhysics(context);
            return ScrollConfiguration(
              behavior: defaultBehavior.copyWith(physics: const BouncingScrollPhysics()),
              child: Builder(
                builder: (BuildContext context) {
                  final ScrollBehavior onceCopiedBehavior = ScrollConfiguration.of(context);
                  onceCopiedPhysics = onceCopiedBehavior.getScrollPhysics(context);
                  return ScrollConfiguration(
                    // Copy again, physics should follow
                    behavior: onceCopiedBehavior.copyWith(),
                    child: Builder(
                      builder: (BuildContext context) {
                        twiceCopiedPhysics = ScrollConfiguration.of(context).getScrollPhysics(context);
                        return SingleChildScrollView(child: Container(height: 1000));
                      }
                    )
                  );
                }
              )
            );
          }
        ),
      ));

      expect(defaultPhysics, const ClampingScrollPhysics(parent: RangeMaintainingScrollPhysics()));
      expect(onceCopiedPhysics, const BouncingScrollPhysics());
      expect(twiceCopiedPhysics, const BouncingScrollPhysics());
    });

    testWidgets('platform', (WidgetTester tester) async {
      // Regression test for https://github.com/flutter/flutter/issues/91673
      late TargetPlatform defaultPlatform;
      late TargetPlatform onceCopiedPlatform;
      late TargetPlatform twiceCopiedPlatform;

      await tester.pumpWidget(ScrollConfiguration(
        // Default ScrollBehavior
        behavior: const ScrollBehavior(),
        child: Builder(
            builder: (BuildContext context) {
              final ScrollBehavior defaultBehavior = ScrollConfiguration.of(context);
              // Copy once to change physics
              defaultPlatform = defaultBehavior.getPlatform(context);
              return ScrollConfiguration(
                  behavior: defaultBehavior.copyWith(platform: TargetPlatform.fuchsia),
                  child: Builder(
                      builder: (BuildContext context) {
                        final ScrollBehavior onceCopiedBehavior = ScrollConfiguration.of(context);
                        onceCopiedPlatform = onceCopiedBehavior.getPlatform(context);
                        return ScrollConfiguration(
                          // Copy again, physics should follow
                            behavior: onceCopiedBehavior.copyWith(),
                            child: Builder(
                                builder: (BuildContext context) {
                                  twiceCopiedPlatform = ScrollConfiguration.of(context).getPlatform(context);
                                  return SingleChildScrollView(child: Container(height: 1000));
                                }
                            )
                        );
                      }
                  )
              );
            }
        ),
      ));

      expect(defaultPlatform, TargetPlatform.android);
      expect(onceCopiedPlatform, TargetPlatform.fuchsia);
      expect(twiceCopiedPlatform, TargetPlatform.fuchsia);
    });

    Widget wrap(ScrollBehavior behavior) {
      return Directionality(
          textDirection: TextDirection.ltr,
          child: MediaQuery(
            data: const MediaQueryData(size: Size(500, 500)),
            child: ScrollConfiguration(
                behavior: behavior,
                child: Builder(
                    builder: (BuildContext context) => SingleChildScrollView(child: Container(height: 1000))
                )
            ),
          )
      );
    }

    testWidgets('scrollbar', (WidgetTester tester) async {
      // Regression test for https://github.com/flutter/flutter/issues/91673
      const  ScrollBehavior defaultBehavior = ScrollBehavior();
      await tester.pumpWidget(wrap(defaultBehavior));
      // Default adds a scrollbar
      expect(find.byType(RawScrollbar), findsOneWidget);
      final ScrollBehavior onceCopiedBehavior = defaultBehavior.copyWith(scrollbars: false);

      await tester.pumpWidget(wrap(onceCopiedBehavior));
      // Copy does not add scrollbar
      expect(find.byType(RawScrollbar), findsNothing);
      final ScrollBehavior twiceCopiedBehavior = onceCopiedBehavior.copyWith();

      await tester.pumpWidget(wrap(twiceCopiedBehavior));
      // Second copy maintains scrollbar setting
      expect(find.byType(RawScrollbar), findsNothing);

      // For default scrollbars
    }, variant: TargetPlatformVariant.desktop());

    testWidgets('overscroll', (WidgetTester tester) async {
      // Regression test for https://github.com/flutter/flutter/issues/91673
      const  ScrollBehavior defaultBehavior = ScrollBehavior();
      await tester.pumpWidget(wrap(defaultBehavior));
      // Default adds a glowing overscroll indicator
      expect(find.byType(GlowingOverscrollIndicator), findsOneWidget);
      final ScrollBehavior onceCopiedBehavior = defaultBehavior.copyWith(overscroll: false);

      await tester.pumpWidget(wrap(onceCopiedBehavior));
      // Copy does not add indicator
      expect(find.byType(GlowingOverscrollIndicator), findsNothing);
      final ScrollBehavior twiceCopiedBehavior = onceCopiedBehavior.copyWith();

      await tester.pumpWidget(wrap(twiceCopiedBehavior));
      // Second copy maintains overscroll setting
      expect(find.byType(GlowingOverscrollIndicator), findsNothing);

      // For default glowing indicator
    }, variant: TargetPlatformVariant.only(TargetPlatform.android));
  });
}
