// 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/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('Simple router basic functionality - synchronized', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            return Text(information!.location!);
          },
        ),
      ),
    ));
    expect(find.text('initial'), findsOneWidget);

    provider.value = const RouteInformation(
      location: 'update',
    );
    await tester.pump();
    expect(find.text('initial'), findsNothing);
    expect(find.text('update'), findsOneWidget);
  });

  testWidgets('Simple router basic functionality - asynchronized', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final SimpleAsyncRouteInformationParser parser = SimpleAsyncRouteInformationParser();
    final SimpleAsyncRouterDelegate delegate = SimpleAsyncRouterDelegate(
      builder: (BuildContext context, RouteInformation? information) {
        if (information == null)
          return const Text('waiting');
        return Text(information.location!);
      },
    );
    await tester.runAsync(() async {
      await tester.pumpWidget(buildBoilerPlate(
        Router<RouteInformation>(
          routeInformationProvider: provider,
          routeInformationParser: parser,
          routerDelegate: delegate,
        ),
      ));
      // Future has not yet completed.
      expect(find.text('waiting'), findsOneWidget);

      await parser.parsingFuture;
      await delegate.setNewRouteFuture;
      await tester.pump();
      expect(find.text('initial'), findsOneWidget);

      provider.value = const RouteInformation(
        location: 'update',
      );
      await tester.pump();
      // Future has not yet completed.
      expect(find.text('initial'), findsOneWidget);

      await parser.parsingFuture;
      await delegate.setNewRouteFuture;
      await tester.pump();
      expect(find.text('update'), findsOneWidget);
    });
  });

  testWidgets('Router.maybeOf can be null', (WidgetTester tester) async {
    final GlobalKey key = GlobalKey();
    await tester.pumpWidget(buildBoilerPlate(
      Text('dummy', key: key),
    ));
    final BuildContext textContext = key.currentContext!;

    // This should not throw error.
    final Router<dynamic>? router = Router.maybeOf(textContext);
    expect(router, isNull);

    expect(
      () => Router.of(textContext),
      throwsA(isFlutterError.having((FlutterError e) => e.message, 'message', startsWith('Router')))
    );
  });

  testWidgets('Simple router can handle pop route', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            return Text(information!.location!);
          },
          onPopRoute: () {
            provider.value = const RouteInformation(
              location: 'popped',
            );
            return SynchronousFuture<bool>(true);
          },
        ),
        backButtonDispatcher: dispatcher,
      ),
    ));
    expect(find.text('initial'), findsOneWidget);

    bool result = false;
    // SynchronousFuture should complete immediately.
    dispatcher.invokeCallback(SynchronousFuture<bool>(false))
      .then((bool data) {
        result = data;
      });
    expect(result, isTrue);

    await tester.pump();
    expect(find.text('popped'), findsOneWidget);
  });

  testWidgets('Router throw when passing routeInformationProvider without routeInformationParser', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    expect(
      () {
        Router<RouteInformation>(
          routeInformationProvider: provider,
          routerDelegate: SimpleRouterDelegate(
            builder: (BuildContext context, RouteInformation? information) {
              return Text(information!.location!);
            },
          ),
        );
      },
      throwsA(isAssertionError.having(
        (AssertionError e) => e.message,
        'message',
        'A routeInformationParser must be provided when a routeInformationProvider or a restorationId is specified.',
      )),
    );
  });

  testWidgets('Router throw when passing restorationId without routeInformationParser', (WidgetTester tester) async {
    expect(
      () {
        Router<RouteInformation>(
          restorationScopeId: 'foo',
          routerDelegate: SimpleRouterDelegate(
            builder: (BuildContext context, RouteInformation? information) {
              return Text(information!.location!);
            },
          ),
        );
      },
      throwsA(isAssertionError.having(
        (AssertionError e) => e.message,
        'message',
        'A routeInformationParser must be provided when a routeInformationProvider or a restorationId is specified.',
      )),
    );
  });

  testWidgets('PopNavigatorRouterDelegateMixin works', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
    final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
      builder: (BuildContext context, RouteInformation? information) {
        return Text(information!.location!);
      },
      onPopPage: (Route<void> route, void result) {
        provider.value = const RouteInformation(
          location: 'popped',
        );
        return route.didPop(result);
      },
    );
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: delegate,
        backButtonDispatcher: dispatcher,
      ),
    ));
    expect(find.text('initial'), findsOneWidget);

    // Pushes a nameless route.
    showDialog<void>(
      useRootNavigator: false,
      context: delegate.navigatorKey.currentContext!,
      builder: (BuildContext context) => const Text('dialog'),
    );
    await tester.pumpAndSettle();
    expect(find.text('dialog'), findsOneWidget);

    // Pops the nameless route and makes sure the initial page is shown.
    bool result = false;
    result = await dispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);

    await tester.pumpAndSettle();
    expect(find.text('initial'), findsOneWidget);
    expect(find.text('dialog'), findsNothing);

    // Pops one more time.
    result = false;
    result = await dispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    await tester.pumpAndSettle();
    expect(find.text('popped'), findsOneWidget);
  });

  testWidgets('Nested routers back button dispatcher works', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            final BackButtonDispatcher innerDispatcher = ChildBackButtonDispatcher(outerDispatcher);
            innerDispatcher.takePriority();
            // Creates the sub-router.
            return Router<RouteInformation>(
              backButtonDispatcher: innerDispatcher,
              routerDelegate: SimpleRouterDelegate(
                builder: (BuildContext context, RouteInformation? innerInformation) {
                  return Text(information!.location!);
                },
                onPopRoute: () {
                  provider.value = const RouteInformation(
                    location: 'popped inner',
                  );
                  return SynchronousFuture<bool>(true);
                },
              ),
            );
          },
          onPopRoute: () {
            provider.value = const RouteInformation(
              location: 'popped outer',
            );
            return SynchronousFuture<bool>(true);
          },
        ),
      ),
    ));
    expect(find.text('initial'), findsOneWidget);

    // The outer dispatcher should trigger the pop on the inner router.
    bool result = false;
    result = await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    await tester.pump();
    expect(find.text('popped inner'), findsOneWidget);
  });

  testWidgets('Nested router back button dispatcher works for multiple children', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    final BackButtonDispatcher innerDispatcher1 = ChildBackButtonDispatcher(outerDispatcher);
    final BackButtonDispatcher innerDispatcher2 = ChildBackButtonDispatcher(outerDispatcher);
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            // Creates the sub-router.
            return Column(
              children: <Widget>[
                Text(information!.location!),
                Router<RouteInformation>(
                  backButtonDispatcher: innerDispatcher1,
                  routerDelegate: SimpleRouterDelegate(
                    builder: (BuildContext context, RouteInformation? innerInformation) {
                      return Container();
                    },
                    onPopRoute: () {
                      provider.value = const RouteInformation(
                        location: 'popped inner1',
                      );
                      return SynchronousFuture<bool>(true);
                    },
                  ),
                ),
                Router<RouteInformation>(
                  backButtonDispatcher: innerDispatcher2,
                  routerDelegate: SimpleRouterDelegate(
                    builder: (BuildContext context, RouteInformation? innerInformation) {
                      return Container();
                    },
                    onPopRoute: () {
                      provider.value = const RouteInformation(
                        location: 'popped inner2',
                      );
                      return SynchronousFuture<bool>(true);
                    },
                  ),
                ),
              ],
            );
          },
          onPopRoute: () {
            provider.value = const RouteInformation(
              location: 'popped outer',
            );
            return SynchronousFuture<bool>(true);
          },
        ),
      ),
    ));
    expect(find.text('initial'), findsOneWidget);

    // If none of the children have taken the priority, the root router handles
    // the pop.
    bool result = false;
    result = await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    await tester.pump();
    expect(find.text('popped outer'), findsOneWidget);

    innerDispatcher1.takePriority();
    result = false;
    result = await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    await tester.pump();
    expect(find.text('popped inner1'), findsOneWidget);

    // The last child dispatcher that took priority handles the pop.
    innerDispatcher2.takePriority();
    result = false;
    result = await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    await tester.pump();
    expect(find.text('popped inner2'), findsOneWidget);
  });

  testWidgets('ChildBackButtonDispatcher can be replaced without calling the takePriority', (WidgetTester tester) async {

    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    BackButtonDispatcher innerDispatcher = ChildBackButtonDispatcher(outerDispatcher);
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            // Creates the sub-router.
            return Column(
              children: <Widget>[
                const Text('initial'),
                Router<RouteInformation>(
                  backButtonDispatcher: innerDispatcher,
                  routerDelegate: SimpleRouterDelegate(
                    builder: (BuildContext context, RouteInformation? innerInformation) {
                      return Container();
                    },
                  ),
                ),
              ],
            );
          },
        ),
      ),
    ));

    // Creates a new child back button dispatcher and rebuild, this will cause
    // the old one to be replaced and discarded.
    innerDispatcher = ChildBackButtonDispatcher(outerDispatcher);
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            // Creates the sub-router.
            return Column(
              children: <Widget>[
                const Text('initial'),
                Router<RouteInformation>(
                  backButtonDispatcher: innerDispatcher,
                  routerDelegate: SimpleRouterDelegate(
                    builder: (BuildContext context, RouteInformation? innerInformation) {
                      return Container();
                    },
                  ),
                ),
              ],
            );
          },
        ),
      ),
    ));

    expect(tester.takeException(), isNull);
  });

testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester tester) async {

    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    final BackButtonDispatcher innerDispatcher1 = ChildBackButtonDispatcher(outerDispatcher);
    final BackButtonDispatcher innerDispatcher2 = ChildBackButtonDispatcher(innerDispatcher1);
    final BackButtonDispatcher innerDispatcher3 = ChildBackButtonDispatcher(innerDispatcher2);
    bool isPopped = false;
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            // Creates the sub-router.
            return Router<RouteInformation>(
              backButtonDispatcher: innerDispatcher1,
              routerDelegate: SimpleRouterDelegate(
                builder: (BuildContext context, RouteInformation? innerInformation) {
                  return Router<RouteInformation>(
                    backButtonDispatcher: innerDispatcher2,
                    routerDelegate: SimpleRouterDelegate(
                      builder: (BuildContext context, RouteInformation? innerInformation) {
                        return Router<RouteInformation>(
                          backButtonDispatcher: innerDispatcher3,
                          routerDelegate: SimpleRouterDelegate(
                            onPopRoute: () {
                              isPopped = true;
                              return SynchronousFuture<bool>(true);
                            },
                            builder: (BuildContext context, RouteInformation? innerInformation) {
                              return Container();
                            },
                          ),
                        );
                      },
                    ),
                  );
                },
              ),
            );
          },
        ),
      ),
    ));
    // This should work without calling the takePriority on the innerDispatcher2
    // and the innerDispatcher1.
    innerDispatcher3.takePriority();
    bool result = false;
    result = await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    expect(isPopped, isTrue);
  });

  testWidgets('router does report URL change correctly', (WidgetTester tester) async {
    RouteInformation? reportedRouteInformation;
    RouteInformationReportingType? reportedType;
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(
      onRouterReport: (RouteInformation information, RouteInformationReportingType type) {
        // Makes sure we only report once after manually cleaning up.
        expect(reportedRouteInformation, isNull);
        expect(reportedType, isNull);
        reportedRouteInformation = information;
        reportedType = type;
      },
    );
    final SimpleRouterDelegate delegate = SimpleRouterDelegate(
      reportConfiguration: true,
      builder: (BuildContext context, RouteInformation? information) {
        return Text(information!.location!);
      },
    );
    delegate.onPopRoute = () {
      delegate.routeInformation = const RouteInformation(
        location: 'popped',
      );
      return SynchronousFuture<bool>(true);
    };
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();

    provider.value = const RouteInformation(
      location: 'initial',
    );

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: delegate,
      ),
    ));
    expect(find.text('initial'), findsOneWidget);
    expect(reportedRouteInformation!.location, 'initial');
    expect(reportedType, RouteInformationReportingType.none);
    reportedRouteInformation = null;
    reportedType = null;
    delegate.routeInformation = const RouteInformation(
      location: 'update',
    );
    await tester.pump();
    expect(find.text('initial'), findsNothing);
    expect(find.text('update'), findsOneWidget);
    expect(reportedRouteInformation!.location, 'update');
    expect(reportedType, RouteInformationReportingType.none);

    // The router should report as non navigation event if only state changes.
    reportedRouteInformation = null;
    reportedType = null;
    delegate.routeInformation = const RouteInformation(
      location: 'update',
      state: 'another state',
    );
    await tester.pump();
    expect(find.text('update'), findsOneWidget);
    expect(reportedRouteInformation!.location, 'update');
    expect(reportedRouteInformation!.state, 'another state');
    expect(reportedType, RouteInformationReportingType.none);

    reportedRouteInformation = null;
    reportedType = null;
    bool result = false;
    result = await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    await tester.pump();
    expect(find.text('popped'), findsOneWidget);
    expect(reportedRouteInformation!.location, 'popped');
    expect(reportedType, RouteInformationReportingType.none);
  });

  testWidgets('router can be forced to recognize or ignore navigating events', (WidgetTester tester) async {
    RouteInformation? reportedRouteInformation;
    RouteInformationReportingType? reportedType;
    bool isNavigating = false;
    late RouteInformation nextRouteInformation;
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(
      onRouterReport: (RouteInformation information, RouteInformationReportingType type) {
        // Makes sure we only report once after manually cleaning up.
        expect(reportedRouteInformation, isNull);
        expect(reportedType, isNull);
        reportedRouteInformation = information;
        reportedType = type;
      },
    );
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true);
    delegate.builder = (BuildContext context, RouteInformation? information) {
      return ElevatedButton(
        child: Text(information!.location!),
        onPressed: () {
          if (isNavigating) {
            Router.navigate(context, () {
              if (delegate.routeInformation != nextRouteInformation)
                delegate.routeInformation = nextRouteInformation;
            });
          } else {
            Router.neglect(context, () {
              if (delegate.routeInformation != nextRouteInformation)
                delegate.routeInformation = nextRouteInformation;
            });
          }
        },
      );
    };
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: delegate,
      ),
    ));
    expect(find.text('initial'), findsOneWidget);
    expect(reportedRouteInformation!.location, 'initial');
    expect(reportedType, RouteInformationReportingType.none);
    reportedType = null;
    reportedRouteInformation = null;

    nextRouteInformation = const RouteInformation(
      location: 'update',
    );
    await tester.tap(find.byType(ElevatedButton));
    await tester.pump();
    expect(find.text('initial'), findsNothing);
    expect(find.text('update'), findsOneWidget);
    expect(reportedType, RouteInformationReportingType.neglect);
    expect(reportedRouteInformation!.location, 'update');
    reportedType = null;
    reportedRouteInformation = null;

    isNavigating = true;
    // This should not trigger any real navigating event because the
    // nextRouteInformation does not change. However, the router should still
    // report a route information because isNavigating = true.
    await tester.tap(find.byType(ElevatedButton));
    await tester.pump();
    expect(reportedType, RouteInformationReportingType.navigate);
    expect(reportedRouteInformation!.location, 'update');
    reportedType = null;
    reportedRouteInformation = null;
  });

  testWidgets('router ignore navigating events updates RouteInformationProvider', (WidgetTester tester) async {
    RouteInformation? updatedRouteInformation;
    late RouteInformation nextRouteInformation;
    RouteInformationReportingType? reportingType;
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(
      onRouterReport: (RouteInformation information, RouteInformationReportingType type) {
        expect(reportingType, isNull);
        expect(updatedRouteInformation, isNull);
        updatedRouteInformation = information;
        reportingType = type;
      },
    );
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true);
    delegate.builder = (BuildContext context, RouteInformation? information) {
      return ElevatedButton(
        child: Text(information!.location!),
        onPressed: () {
          Router.neglect(context, () {
            if (delegate.routeInformation != nextRouteInformation)
              delegate.routeInformation = nextRouteInformation;
          });
        },
      );
    };
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: delegate,
      ),
    ));
    expect(find.text('initial'), findsOneWidget);
    expect(updatedRouteInformation!.location, 'initial');
    expect(reportingType, RouteInformationReportingType.none);
    updatedRouteInformation = null;
    reportingType = null;

    nextRouteInformation = const RouteInformation(
      location: 'update',
    );
    await tester.tap(find.byType(ElevatedButton));
    await tester.pump();
    expect(find.text('initial'), findsNothing);
    expect(find.text('update'), findsOneWidget);
    expect(updatedRouteInformation!.location, 'update');
    expect(reportingType, RouteInformationReportingType.neglect);
  });

  testWidgets('state change without location changes updates RouteInformationProvider', (WidgetTester tester) async {
    RouteInformation? updatedRouteInformation;
    late RouteInformation nextRouteInformation;
    RouteInformationReportingType? reportingType;
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(
      onRouterReport: (RouteInformation information, RouteInformationReportingType type) {
        // This should never be a navigation event.
        expect(reportingType, isNull);
        expect(updatedRouteInformation, isNull);
        updatedRouteInformation = information;
        reportingType = type;
      },
    );
    provider.value = const RouteInformation(
      location: 'initial',
      state: 'state1',
    );
    final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true);
    delegate.builder = (BuildContext context, RouteInformation? information) {
      return ElevatedButton(
        child: Text(information!.location!),
        onPressed: () {
          delegate.routeInformation = nextRouteInformation;
        },
      );
    };
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: delegate,
      ),
    ));
    expect(find.text('initial'), findsOneWidget);
    expect(updatedRouteInformation!.location, 'initial');
    expect(reportingType, RouteInformationReportingType.none);
    updatedRouteInformation = null;
    reportingType = null;

    nextRouteInformation = const RouteInformation(
      location: 'initial',
      state: 'state2',
    );
    await tester.tap(find.byType(ElevatedButton));
    await tester.pump();
    expect(updatedRouteInformation!.location, 'initial');
    expect(updatedRouteInformation!.state, 'state2');
    expect(reportingType, RouteInformationReportingType.none);
  });

  testWidgets('PlatformRouteInformationProvider works', (WidgetTester tester) async {
    final RouteInformationProvider provider = PlatformRouteInformationProvider(
      initialRouteInformation: const RouteInformation(
        location: 'initial',
      ),
    );
    final SimpleRouterDelegate delegate = SimpleRouterDelegate(
      builder: (BuildContext context, RouteInformation? information) {
        final List<Widget> children = <Widget>[];
        if (information!.location! != null)
          children.add(Text(information.location!));
        if (information.state != null)
          children.add(Text(information.state.toString()));
        return Column(
          children: children,
        );
      },
    );

    await tester.pumpWidget(MaterialApp.router(
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: delegate,
    ));
    expect(find.text('initial'), findsOneWidget);

    // Pushes through the `pushRouteInformation` in the navigation method channel.
    const Map<String, dynamic> testRouteInformation = <String, dynamic>{
      'location': 'testRouteName',
      'state': 'state',
    };
    final ByteData routerMessage = const JSONMethodCodec().encodeMethodCall(
      const MethodCall('pushRouteInformation', testRouteInformation),
    );
    await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', routerMessage, (_) { });
    await tester.pump();
    expect(find.text('testRouteName'), findsOneWidget);
    expect(find.text('state'), findsOneWidget);

    // Pushes through the `pushRoute` in the navigation method channel.
    const String testRouteName = 'newTestRouteName';
    final ByteData message = const JSONMethodCodec().encodeMethodCall(
      const MethodCall('pushRoute', testRouteName),
    );
    await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
    await tester.pump();
    expect(find.text('newTestRouteName'), findsOneWidget);
  });

  testWidgets('PlatformRouteInformationProvider updates route information', (WidgetTester tester) async {
    final List<MethodCall> log = <MethodCall>[];
    TestDefaultBinaryMessengerBinding
      .instance!
      .defaultBinaryMessenger
      .setMockMethodCallHandler(
        SystemChannels.navigation,
        (MethodCall methodCall) async {
          log.add(methodCall);
        }
      );
    final RouteInformationProvider provider = PlatformRouteInformationProvider(
      initialRouteInformation: const RouteInformation(
        location: 'initial',
      ),
    );

    log.clear();
    provider.routerReportsNewRouteInformation(const RouteInformation(location: 'a', state: true), type: RouteInformationReportingType.none);
    // Implicit reporting pushes new history entry if the location changes.
    expect(log, <Object>[
      isMethodCall('selectMultiEntryHistory', arguments: null),
      isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'a', 'state': true, 'replace': false }),
    ]);
    log.clear();
    provider.routerReportsNewRouteInformation(const RouteInformation(location: 'a', state: false), type: RouteInformationReportingType.none);
    // Since the location is the same, the provider sends replaces message.
    expect(log, <Object>[
      isMethodCall('selectMultiEntryHistory', arguments: null),
      isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'a', 'state': false, 'replace': true }),
    ]);

    log.clear();
    provider.routerReportsNewRouteInformation(const RouteInformation(location: 'b', state: false), type: RouteInformationReportingType.neglect);
    expect(log, <Object>[
      isMethodCall('selectMultiEntryHistory', arguments: null),
      isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'b', 'state': false, 'replace': true }),
    ]);

    log.clear();
    provider.routerReportsNewRouteInformation(const RouteInformation(location: 'b', state: false), type: RouteInformationReportingType.navigate);
    expect(log, <Object>[
      isMethodCall('selectMultiEntryHistory', arguments: null),
      isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'b', 'state': false, 'replace': false }),
    ]);
  });

  testWidgets('RootBackButtonDispatcher works', (WidgetTester tester) async {
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    final RouteInformationProvider provider = PlatformRouteInformationProvider(
      initialRouteInformation: const RouteInformation(
        location: 'initial',
      ),
    );
    final SimpleRouterDelegate delegate = SimpleRouterDelegate(
      reportConfiguration: true,
      builder: (BuildContext context, RouteInformation? information) {
        return Text(information!.location!);
      },
    );
    delegate.onPopRoute = () {
      delegate.routeInformation = const RouteInformation(
        location: 'popped',
      );
      return SynchronousFuture<bool>(true);
    };

    await tester.pumpWidget(MaterialApp.router(
      backButtonDispatcher: outerDispatcher,
      routeInformationProvider: provider,
      routeInformationParser: SimpleRouteInformationParser(),
      routerDelegate: delegate,
    ));
    expect(find.text('initial'), findsOneWidget);

    // Pop route through the message channel.
    final ByteData message = const JSONMethodCodec().encodeMethodCall(const MethodCall('popRoute'));
    await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
    await tester.pump();
    expect(find.text('popped'), findsOneWidget);
  });

  testWidgets('BackButtonListener takes priority over root back dispatcher', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            // Creates the sub-router.
            return Column(
              children: <Widget>[
                Text(information!.location!),
                BackButtonListener(
                  child: Container(),
                  onBackButtonPressed: () {
                      provider.value = const RouteInformation(
                        location: 'popped inner1',
                      );
                      return SynchronousFuture<bool>(true);
                    },
                ),
              ],
            );
          },
          onPopRoute: () {
            provider.value = const RouteInformation(
              location: 'popped outer',
            );
            return SynchronousFuture<bool>(true);
          },
        ),
      ),
    ));
    expect(find.text('initial'), findsOneWidget);

    bool result = false;
    result = await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    await tester.pump();
    expect(find.text('popped inner1'), findsOneWidget);
  });

  testWidgets('BackButtonListener updates callback if it has been changed', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    final SimpleRouterDelegate routerDelegate = SimpleRouterDelegate()
      ..builder = (BuildContext context, RouteInformation? information) {
            // Creates the sub-router.
            return Column(
              children: <Widget>[
                Text(information!.location!),
                BackButtonListener(
                  child: Container(),
                  onBackButtonPressed: () {
                      provider.value = const RouteInformation(
                        location: 'first callback',
                      );
                      return SynchronousFuture<bool>(true);
                    },
                ),
              ],
            );
          }
        ..onPopRoute = () {
            provider.value = const RouteInformation(
              location: 'popped outer',
            );
            return SynchronousFuture<bool>(true);
          };

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: routerDelegate,
      ),
    ));

    routerDelegate
      ..builder = (BuildContext context, RouteInformation? information) {
        // Creates the sub-router.
        return Column(
          children: <Widget>[
            Text(information!.location!),
            BackButtonListener(
              child: Container(),
              onBackButtonPressed: () {
                  provider.value = const RouteInformation(
                    location: 'second callback',
                  );
                  return SynchronousFuture<bool>(true);
                },
            ),
          ],
        );
      }
      ..onPopRoute = () {
        provider.value = const RouteInformation(
          location: 'popped outer',
        );
        return SynchronousFuture<bool>(true);
      };

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: routerDelegate,
      ),
    ));
    await tester.pump();
    await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    await tester.pump();
    expect(find.text('second callback'), findsOneWidget);
  });

  testWidgets('BackButtonListener clears callback if it is disposed', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    final SimpleRouterDelegate routerDelegate = SimpleRouterDelegate()
      ..builder = (BuildContext context, RouteInformation? information) {
            // Creates the sub-router.
            return Column(
              children: <Widget>[
                Text(information!.location!),
                BackButtonListener(
                  child: Container(),
                  onBackButtonPressed: () {
                      provider.value = const RouteInformation(
                        location: 'first callback',
                      );
                      return SynchronousFuture<bool>(true);
                    },
                ),
              ],
            );
          }
        ..onPopRoute = () {
            provider.value = const RouteInformation(
              location: 'popped outer',
            );
            return SynchronousFuture<bool>(true);
          };

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: routerDelegate,
      ),
    ));

    routerDelegate
      ..builder = (BuildContext context, RouteInformation? information) {
        // Creates the sub-router.
        return Column(
          children: <Widget>[
            Text(information!.location!),
          ],
        );
      }
      ..onPopRoute = () {
        provider.value = const RouteInformation(
          location: 'popped outer',
        );
        return SynchronousFuture<bool>(true);
      };

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: routerDelegate,
      ),
    ));
    await tester.pump();
    await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    await tester.pump();
    expect(find.text('popped outer'), findsOneWidget);
  });

  testWidgets('Nested backButtonListener should take priority', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            // Creates the sub-router.
            return Column(
              children: <Widget>[
                Text(information!.location!),
                BackButtonListener(
                  child: BackButtonListener(
                    child: Container(),
                    onBackButtonPressed: () {
                      provider.value = const RouteInformation(
                        location: 'popped inner2',
                      );
                      return SynchronousFuture<bool>(true);
                    },
                  ),
                  onBackButtonPressed: () {
                      provider.value = const RouteInformation(
                        location: 'popped inner1',
                      );
                      return SynchronousFuture<bool>(true);
                    },
                ),
              ],
            );
          },
          onPopRoute: () {
            provider.value = const RouteInformation(
              location: 'popped outer',
            );
            return SynchronousFuture<bool>(true);
          },
        ),
      ),
    ));
    expect(find.text('initial'), findsOneWidget);

    bool result = false;
    result = await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    await tester.pump();
    expect(find.text('popped inner2'), findsOneWidget);
  });

  testWidgets('Nested backButtonListener that returns false should call next on the line', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext context, RouteInformation? information) {
            // Creates the sub-router.
            return Column(
              children: <Widget>[
                Text(information!.location!),
                BackButtonListener(
                  child: BackButtonListener(
                    child: Container(),
                    onBackButtonPressed: () {
                      provider.value = const RouteInformation(
                        location: 'popped inner2',
                      );
                      return SynchronousFuture<bool>(false);
                    },
                  ),
                  onBackButtonPressed: () {
                      provider.value = const RouteInformation(
                        location: 'popped inner1',
                      );
                      return SynchronousFuture<bool>(true);
                    },
                ),
              ],
            );
          },
          onPopRoute: () {
            provider.value = const RouteInformation(
              location: 'popped outer',
            );
            return SynchronousFuture<bool>(true);
          },
        ),
      ),
    ));
    expect(find.text('initial'), findsOneWidget);

    bool result = false;
    result = await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    expect(result, isTrue);
    await tester.pump();
    expect(find.text('popped inner1'), findsOneWidget);
  });

  testWidgets('`didUpdateWidget` test', (WidgetTester tester) async {
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
    provider.value = const RouteInformation(
      location: 'initial',
    );
    final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
    late StateSetter setState;
    String location = 'first callback';
    final SimpleRouterDelegate routerDelegate = SimpleRouterDelegate()
      ..builder = (BuildContext context, RouteInformation? information) {
        // Creates the sub-router.
        return Column(
          children: <Widget>[
            Text(information!.location!),
            StatefulBuilder(
              builder: (BuildContext context, StateSetter setter) {
                setState = setter;
                return BackButtonListener(
                  child: Container(),
                  onBackButtonPressed: () {
                    provider.value = RouteInformation(
                      location: location,
                    );
                    return SynchronousFuture<bool>(true);
                  },
                );
              },
            ),
          ],
        );
      }
      ..onPopRoute = () {
        provider.value = const RouteInformation(
          location: 'popped outer',
        );
        return SynchronousFuture<bool>(true);
      };

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        backButtonDispatcher: outerDispatcher,
        routeInformationProvider: provider,
        routeInformationParser: SimpleRouteInformationParser(),
        routerDelegate: routerDelegate,
      ),
    ));

    // Only update BackButtonListener widget.
    setState(() {
      location = 'second callback';
    });

    await tester.pump();
    await outerDispatcher.invokeCallback(SynchronousFuture<bool>(false));
    await tester.pump();
    expect(find.text('second callback'), findsOneWidget);
  });

  testWidgets('Router reports location if it is different from location given by OS', (WidgetTester tester) async {
    final List<RouteInformation> reportedRouteInformation = <RouteInformation>[];
    final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(
      onRouterReport: (RouteInformation info, RouteInformationReportingType type) => reportedRouteInformation.add(info),
    )..value = const RouteInformation(location: '/home');

    await tester.pumpWidget(buildBoilerPlate(
      Router<RouteInformation>(
        routeInformationProvider: provider,
        routeInformationParser: RedirectingInformationParser(<String, RouteInformation>{
          '/doesNotExist' : const RouteInformation(location: '/404'),
        }),
        routerDelegate: SimpleRouterDelegate(
          builder: (BuildContext _, RouteInformation? info) => Text('Current route: ${info?.location}'),
          reportConfiguration: true,
        ),
      ),
    ));

    expect(find.text('Current route: /home'), findsOneWidget);
    expect(reportedRouteInformation.single.location, '/home');

    provider.value = const RouteInformation(location: '/doesNotExist');
    await tester.pump();

    expect(find.text('Current route: /404'), findsOneWidget);
    expect(reportedRouteInformation[1].location, '/404');
  });
}

Widget buildBoilerPlate(Widget child) {
  return MaterialApp(
    home: Scaffold(
      body: child,
    ),
  );
}

typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation?);
typedef SimpleRouterDelegatePopRoute = Future<bool> Function();
typedef SimpleNavigatorRouterDelegatePopPage<T> = bool Function(Route<T> route, T result);
typedef RouterReportRouterInformation = void Function(RouteInformation, RouteInformationReportingType);

class SimpleRouteInformationParser extends RouteInformationParser<RouteInformation> {
  SimpleRouteInformationParser();

  @override
  Future<RouteInformation> parseRouteInformation(RouteInformation information) {
    return SynchronousFuture<RouteInformation>(information);
  }

  @override
  RouteInformation restoreRouteInformation(RouteInformation configuration) {
    return configuration;
  }
}

class SimpleRouterDelegate extends RouterDelegate<RouteInformation> with ChangeNotifier {
  SimpleRouterDelegate({
    this.builder,
    this.onPopRoute,
    this.reportConfiguration = false,
  });

  RouteInformation? get routeInformation => _routeInformation;
  RouteInformation? _routeInformation;
  set routeInformation(RouteInformation? newValue) {
    _routeInformation = newValue;
    notifyListeners();
  }

  SimpleRouterDelegateBuilder? builder;
  SimpleRouterDelegatePopRoute? onPopRoute;
  final bool reportConfiguration;

  @override
  RouteInformation? get currentConfiguration {
    if (reportConfiguration)
      return routeInformation;
    return null;
  }

  @override
  Future<void> setNewRoutePath(RouteInformation configuration) {
    _routeInformation = configuration;
    return SynchronousFuture<void>(null);
  }

  @override
  Future<bool> popRoute() {
    return onPopRoute?.call() ?? SynchronousFuture<bool>(true);
  }

  @override
  Widget build(BuildContext context) => builder!(context, routeInformation);
}

class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> with PopNavigatorRouterDelegateMixin<RouteInformation>, ChangeNotifier {
  SimpleNavigatorRouterDelegate({
    required this.builder,
    required this.onPopPage,
  });

  @override
  GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

  RouteInformation get routeInformation => _routeInformation;
  late RouteInformation _routeInformation;
  set routeInformation(RouteInformation newValue) {
    _routeInformation = newValue;
    notifyListeners();
  }

  SimpleRouterDelegateBuilder builder;
  SimpleNavigatorRouterDelegatePopPage<void> onPopPage;

  @override
  Future<void> setNewRoutePath(RouteInformation configuration) {
    _routeInformation = configuration;
    return SynchronousFuture<void>(null);
  }

  bool _handlePopPage(Route<void> route, void data) {
    return onPopPage(route, data);
  }

  @override
  Widget build(BuildContext context) {
    return Navigator(
      key: navigatorKey,
      onPopPage: _handlePopPage,
      pages: <Page<void>>[
        // We need at least two pages for the pop to propagate through.
        // Otherwise, the navigator will bubble the pop to the system navigator.
        const MaterialPage<void>(
          child: Text('base'),
        ),
        MaterialPage<void>(
          key: ValueKey<String>(routeInformation.location!),
          child: builder(context, routeInformation),
        ),
      ],
    );
  }
}

class SimpleRouteInformationProvider extends RouteInformationProvider with ChangeNotifier {
  SimpleRouteInformationProvider({
    this.onRouterReport,
  });

  RouterReportRouterInformation? onRouterReport;

  @override
  RouteInformation get value => _value;
  late RouteInformation _value;
  set value(RouteInformation newValue) {
    _value = newValue;
    notifyListeners();
  }

  @override
  void routerReportsNewRouteInformation(RouteInformation routeInformation, {required RouteInformationReportingType type}) {
    _value = routeInformation;
    onRouterReport?.call(routeInformation, type);
  }
}

class SimpleAsyncRouteInformationParser extends RouteInformationParser<RouteInformation> {
  SimpleAsyncRouteInformationParser();

  late Future<RouteInformation> parsingFuture;

  @override
  Future<RouteInformation> parseRouteInformation(RouteInformation information) {
    return parsingFuture = Future<RouteInformation>.value(information);
  }

  @override
  RouteInformation restoreRouteInformation(RouteInformation configuration) {
    return configuration;
  }
}

class SimpleAsyncRouterDelegate extends RouterDelegate<RouteInformation> with ChangeNotifier {
  SimpleAsyncRouterDelegate({
    required this.builder,
  });

  RouteInformation? get routeInformation => _routeInformation;
  RouteInformation? _routeInformation;
  set routeInformation(RouteInformation? newValue) {
    _routeInformation = newValue;
    notifyListeners();
  }

  SimpleRouterDelegateBuilder builder;
  late Future<void> setNewRouteFuture;

  @override
  Future<void> setNewRoutePath(RouteInformation configuration) {
    _routeInformation = configuration;
    return setNewRouteFuture = Future<void>.value();
  }

  @override
  Future<bool> popRoute() {
    return Future<bool>.value(true);
  }

  @override
  Widget build(BuildContext context) => builder(context, routeInformation);
}

class RedirectingInformationParser extends RouteInformationParser<RouteInformation> {

  RedirectingInformationParser(this.redirects);

  final Map<String, RouteInformation> redirects;

  @override
  Future<RouteInformation> parseRouteInformation(RouteInformation information) {
    return SynchronousFuture<RouteInformation>(redirects[information.location] ?? information);
  }

  @override
  RouteInformation restoreRouteInformation(RouteInformation configuration) {
    return configuration;
  }
}
