// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@TestOn('chrome')

import 'dart:ui';

import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class OnTapPage extends StatelessWidget {
  const OnTapPage({Key key, this.id, this.onTap}) : super(key: key);

  final String id;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Page $id')),
      body: GestureDetector(
        onTap: onTap,
        behavior: HitTestBehavior.opaque,
        child: Container(
          child: Center(
            child: Text(id, style: Theme.of(context).textTheme.display2),
          ),
        ),
      ),
    );
  }
}

void main() {
  testWidgets('Push and Pop should send platform messages',
      (WidgetTester tester) async {
    final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
      '/': (BuildContext context) => OnTapPage(
          id: '/',
          onTap: () {
            Navigator.pushNamed(context, '/A');
          }),
      '/A': (BuildContext context) => OnTapPage(
          id: 'A',
          onTap: () {
            Navigator.pop(context);
          }),
    };

    final List<MethodCall> log = <MethodCall>[];

    SystemChannels.navigation
        .setMockMethodCallHandler((MethodCall methodCall) async {
      log.add(methodCall);
    });

    await tester.pumpWidget(MaterialApp(
      routes: routes,
    ));

    expect(log, hasLength(1));
    expect(
        log.last,
        isMethodCall(
          'routePushed',
          arguments: <String, dynamic>{
            'previousRouteName': null,
            'routeName': '/'
          },
        ));

    await tester.tap(find.text('/'));
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));

    expect(log, hasLength(2));
    expect(
        log.last,
        isMethodCall(
          'routePushed',
          arguments: <String, dynamic>{
            'previousRouteName': '/',
            'routeName': '/A'
          },
        ));

    await tester.tap(find.text('A'));
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));

    expect(log, hasLength(3));
    expect(
        log.last,
        isMethodCall(
          'routePopped',
          arguments: <String, dynamic>{
            'previousRouteName': '/',
            'routeName': '/A'
          },
        ));
  });

  testWidgets('Replace should send platform messages',
      (WidgetTester tester) async {
    final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
      '/': (BuildContext context) => OnTapPage(
          id: '/',
          onTap: () {
            Navigator.pushNamed(context, '/A');
          }),
      '/A': (BuildContext context) => OnTapPage(
          id: 'A',
          onTap: () {
            Navigator.pushReplacementNamed(context, '/B');
          }),
      '/B': (BuildContext context) => OnTapPage(id: 'B', onTap: () {}),
    };

    final List<MethodCall> log = <MethodCall>[];

    SystemChannels.navigation
        .setMockMethodCallHandler((MethodCall methodCall) async {
      log.add(methodCall);
    });

    await tester.pumpWidget(MaterialApp(
      routes: routes,
    ));

    expect(log, hasLength(1));
    expect(
        log.last,
        isMethodCall(
          'routePushed',
          arguments: <String, dynamic>{
            'previousRouteName': null,
            'routeName': '/'
          },
        ));

    await tester.tap(find.text('/'));
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));

    expect(log, hasLength(2));
    expect(
        log.last,
        isMethodCall(
          'routePushed',
          arguments: <String, dynamic>{
            'previousRouteName': '/',
            'routeName': '/A'
          },
        ));

    await tester.tap(find.text('A'));
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));

    expect(log, hasLength(3));
    expect(
        log.last,
        isMethodCall(
          'routeReplaced',
          arguments: <String, dynamic>{
            'previousRouteName': '/A',
            'routeName': '/B'
          },
        ));
  });
}