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

void main() {
  testWidgets('shows title', (WidgetTester tester) async {
    const Widget title = Text('CupertinoListTile');

    await tester.pumpWidget(
      const CupertinoApp(
        home: Center(
          child: CupertinoListTile(
            title: title,
          ),
        ),
      ),
    );

    expect(tester.widget<Text>(find.byType(Text)), title);
    expect(find.text('CupertinoListTile'), findsOneWidget);
  });

  testWidgets('shows subtitle', (WidgetTester tester) async {
    const Widget subtitle = Text('CupertinoListTile subtitle');

    await tester.pumpWidget(
      const CupertinoApp(
        home: Center(
          child: CupertinoListTile(
            title: Icon(CupertinoIcons.add),
            subtitle: subtitle,
          ),
        ),
      ),
    );

    expect(tester.widget<Text>(find.byType(Text)), subtitle);
    expect(find.text('CupertinoListTile subtitle'), findsOneWidget);
  });

  testWidgets('shows additionalInfo', (WidgetTester tester) async {
    const Widget additionalInfo = Text('Not Connected');

    await tester.pumpWidget(
      const CupertinoApp(
        home: Center(
          child: CupertinoListTile(
            title: Icon(CupertinoIcons.add),
            additionalInfo: additionalInfo,
          ),
        ),
      ),
    );

    expect(tester.widget<Text>(find.byType(Text)), additionalInfo);
    expect(find.text('Not Connected'), findsOneWidget);
  });

  testWidgets('shows trailing', (WidgetTester tester) async {
    const Widget trailing = CupertinoListTileChevron();

    await tester.pumpWidget(
      const CupertinoApp(
        home: Center(
          child: CupertinoListTile(
            title: Icon(CupertinoIcons.add),
            trailing: trailing,
          ),
        ),
      ),
    );

    expect(tester.widget<CupertinoListTileChevron>(find.byType(CupertinoListTileChevron)), trailing);
  });

  testWidgets('shows leading', (WidgetTester tester) async {
    const Widget leading = Icon(CupertinoIcons.add);

    await tester.pumpWidget(
      const CupertinoApp(
        home: Center(
          child: CupertinoListTile(
            leading: leading,
            title: Text('CupertinoListTile'),
          ),
        ),
      ),
    );

    expect(tester.widget<Icon>(find.byType(Icon)), leading);
  });

  testWidgets('sets backgroundColor', (WidgetTester tester) async {
    const Color backgroundColor = CupertinoColors.systemRed;

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: MediaQuery(
          data: const MediaQueryData(),
          child: CupertinoListSection(
            children: const <Widget>[
              CupertinoListTile(
                title: Text('CupertinoListTile'),
                backgroundColor: backgroundColor,
              ),
            ],
          ),
        ),
      ),
    );

    // Container inside CupertinoListTile is the second one in row.
    final Container container = tester.widgetList<Container>(find.byType(Container)).elementAt(1);
    expect(container.color, backgroundColor);
  });

  testWidgets('does not change backgroundColor when tapped if onTap is not provided', (WidgetTester tester) async {
    const Color backgroundColor = CupertinoColors.systemBlue;
    const Color backgroundColorActivated = CupertinoColors.systemRed;

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: MediaQuery(
          data: const MediaQueryData(),
          child: CupertinoListSection(
            children: const <Widget>[
              CupertinoListTile(
                title: Text('CupertinoListTile'),
                backgroundColor: backgroundColor,
                backgroundColorActivated: backgroundColorActivated,
              ),
            ],
          ),
        ),
      ),
    );

    await tester.tap(find.byType(CupertinoListTile));
    await tester.pump();

    // Container inside CupertinoListTile is the second one in row.
    final Container container = tester.widgetList<Container>(find.byType(Container)).elementAt(1);
    expect(container.color, backgroundColor);
  });

  testWidgets('changes backgroundColor when tapped if onTap is provided', (WidgetTester tester) async {
    const Color backgroundColor = CupertinoColors.systemBlue;
    const Color backgroundColorActivated = CupertinoColors.systemRed;

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: MediaQuery(
          data: const MediaQueryData(),
          child: CupertinoListSection(
            children: <Widget>[
              CupertinoListTile(
                title: const Text('CupertinoListTile'),
                backgroundColor: backgroundColor,
                backgroundColorActivated: backgroundColorActivated,
                onTap: () async { await Future<void>.delayed(const Duration(milliseconds: 1), () {}); },
              ),
            ],
          ),
        ),
      ),
    );

    // Container inside CupertinoListTile is the second one in row.
    Container container = tester.widgetList<Container>(find.byType(Container)).elementAt(1);
    expect(container.color, backgroundColor);

    // Pump only one frame so the color change persists.
    await tester.tap(find.byType(CupertinoListTile));
    await tester.pump();

    // Container inside CupertinoListTile is the second one in row.
    container = tester.widgetList<Container>(find.byType(Container)).elementAt(1);
    expect(container.color, backgroundColorActivated);

    // Pump the rest of the frames to complete the test.
    await tester.pumpAndSettle();
  });

  testWidgets('does not contain GestureDetector if onTap is not provided', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: MediaQuery(
          data: const MediaQueryData(),
          child: CupertinoListSection(
            children: const <Widget>[
              CupertinoListTile(
                title: Text('CupertinoListTile'),
              ),
            ],
          ),
        ),
      ),
    );

    // Container inside CupertinoListTile is the second one in row.
    expect(find.byType(GestureDetector), findsNothing);
  });

  testWidgets('contains GestureDetector if onTap is provided', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: MediaQuery(
          data: const MediaQueryData(),
          child: CupertinoListSection(
            children: <Widget>[
              CupertinoListTile(
                title: const Text('CupertinoListTile'),
                onTap: () async {},
              ),
            ],
          ),
        ),
      ),
    );

    // Container inside CupertinoListTile is the second one in row.
    expect(find.byType(GestureDetector), findsOneWidget);
  });

  testWidgets('resets the background color when navigated back', (WidgetTester tester) async {
    const Color backgroundColor = CupertinoColors.systemBlue;
    const Color backgroundColorActivated = CupertinoColors.systemRed;

    await tester.pumpWidget(
      CupertinoApp(
        home: Builder(
          builder: (BuildContext context) {
             final Widget secondPage = Center(
              child: CupertinoButton(
                child: const Text('Go back'),
                onPressed: () => Navigator.of(context).pop<void>(),
              ),
            );
            return Center(
              child: Directionality(
                textDirection: TextDirection.ltr,
                child: MediaQuery(
                  data: const MediaQueryData(),
                  child:CupertinoListTile(
                    title: const Text('CupertinoListTile'),
                    backgroundColor: backgroundColor,
                    backgroundColorActivated: backgroundColorActivated,
                    onTap: () => Navigator.of(context).push(CupertinoPageRoute<Widget>(
                      builder: (BuildContext context) => secondPage,
                    )),
                  ),
                ),
              ),
            );
          },
        ),
      ),
    );

    // Navigate to second page.
    await tester.tap(find.byType(CupertinoListTile));
    await tester.pumpAndSettle();

    // Go back to first page.
    await tester.tap(find.byType(CupertinoButton));
    await tester.pumpAndSettle();

    // Container inside CupertinoListTile is the second one in row.
    final Container container = tester.widget<Container>(find.byType(Container));
    expect(container.color, backgroundColor);
  });

  group('alignment of widgets for left-to-right', () {
    testWidgets('leading is on the left of title', (WidgetTester tester) async {
      const Widget title = Text('CupertinoListTile');
      const Widget leading = Icon(CupertinoIcons.add);

      await tester.pumpWidget(
        const CupertinoApp(
          home: Center(
            child: Directionality(
              textDirection: TextDirection.ltr,
              child: CupertinoListTile(
                title: title,
                leading: leading,
              ),
            ),
          ),
        ),
      );

      final Offset foundTitle = tester.getTopLeft(find.byType(Text));
      final Offset foundLeading = tester.getTopRight(find.byType(Icon));

      expect(foundTitle.dx > foundLeading.dx, true);
    });

    testWidgets('subtitle is placed below title and aligned on left', (WidgetTester tester) async {
      const Widget title = Text('CupertinoListTile title');
      const Widget subtitle = Text('CupertinoListTile subtitle');

      await tester.pumpWidget(
        const CupertinoApp(
          home: Center(
            child: Directionality(
              textDirection: TextDirection.ltr,
              child: CupertinoListTile(
                title: title,
                subtitle: subtitle,
              ),
            ),
          ),
        ),
      );

      final Offset foundTitle = tester.getBottomLeft(find.text('CupertinoListTile title'));
      final Offset foundSubtitle = tester.getTopLeft(find.text('CupertinoListTile subtitle'));

      expect(foundTitle.dx, equals(foundSubtitle.dx));
      expect(foundTitle.dy < foundSubtitle.dy, isTrue);
    });

    testWidgets('additionalInfo is on the right of title', (WidgetTester tester) async {
      const Widget title = Text('CupertinoListTile');
      const Widget additionalInfo = Text('Not Connected');

      await tester.pumpWidget(
        const CupertinoApp(
          home: Center(
            child: Directionality(
              textDirection: TextDirection.ltr,
              child: CupertinoListTile(
                title: title,
                additionalInfo: additionalInfo,
              ),
            ),
          ),
        ),
      );

      final Offset foundTitle = tester.getTopRight(find.text('CupertinoListTile'));
      final Offset foundInfo = tester.getTopLeft(find.text('Not Connected'));

      expect(foundTitle.dx < foundInfo.dx, isTrue);
    });

    testWidgets('trailing is on the right of additionalInfo', (WidgetTester tester) async {
      const Widget title = Text('CupertinoListTile');
      const Widget additionalInfo = Text('Not Connected');
      const Widget trailing = CupertinoListTileChevron();

      await tester.pumpWidget(
        const CupertinoApp(
          home: Center(
            child: Directionality(
              textDirection: TextDirection.ltr,
              child: CupertinoListTile(
                title: title,
                additionalInfo: additionalInfo,
                trailing: trailing,
              ),
            ),
          ),
        ),
      );

      final Offset foundInfo = tester.getTopRight(find.text('Not Connected'));
      final Offset foundTrailing = tester.getTopLeft(find.byType(CupertinoListTileChevron));

      expect(foundInfo.dx < foundTrailing.dx, isTrue);
    });
  });

  group('alignment of widgets for right-to-left', () {
    testWidgets('leading is on the right of title', (WidgetTester tester) async {
      const Widget title = Text('CupertinoListTile');
      const Widget leading = Icon(CupertinoIcons.add);

      await tester.pumpWidget(
        const CupertinoApp(
          home: Center(
            child: Directionality(
              textDirection: TextDirection.rtl,
              child: CupertinoListTile(
                title: title,
                leading: leading,
              ),
            ),
          ),
        ),
      );

      final Offset foundTitle = tester.getTopRight(find.byType(Text));
      final Offset foundLeading = tester.getTopLeft(find.byType(Icon));

      expect(foundTitle.dx < foundLeading.dx, true);
    });

    testWidgets('subtitle is placed below title and aligned on right', (WidgetTester tester) async {
      const Widget title = Text('CupertinoListTile title');
      const Widget subtitle = Text('CupertinoListTile subtitle');

      await tester.pumpWidget(
        const CupertinoApp(
          home: Center(
            child: Directionality(
              textDirection: TextDirection.rtl,
              child: CupertinoListTile(
                title: title,
                subtitle: subtitle,
              ),
            ),
          ),
        ),
      );

      final Offset foundTitle = tester.getBottomRight(find.text('CupertinoListTile title'));
      final Offset foundSubtitle = tester.getTopRight(find.text('CupertinoListTile subtitle'));

      expect(foundTitle.dx, equals(foundSubtitle.dx));
      expect(foundTitle.dy < foundSubtitle.dy, isTrue);
    });

    testWidgets('additionalInfo is on the left of title', (WidgetTester tester) async {
      const Widget title = Text('CupertinoListTile');
      const Widget additionalInfo = Text('Not Connected');

      await tester.pumpWidget(
        const CupertinoApp(
          home: Center(
            child: Directionality(
              textDirection: TextDirection.rtl,
              child: CupertinoListTile(
                title: title,
                additionalInfo: additionalInfo,
              ),
            ),
          ),
        ),
      );

      final Offset foundTitle = tester.getTopLeft(find.text('CupertinoListTile'));
      final Offset foundInfo = tester.getTopRight(find.text('Not Connected'));

      expect(foundTitle.dx > foundInfo.dx, isTrue);
    });

    testWidgets('trailing is on the left of additionalInfo', (WidgetTester tester) async {
      const Widget title = Text('CupertinoListTile');
      const Widget additionalInfo = Text('Not Connected');
      const Widget trailing = CupertinoListTileChevron();

      await tester.pumpWidget(
        const CupertinoApp(
          home: Center(
            child: Directionality(
              textDirection: TextDirection.rtl,
              child: CupertinoListTile(
                title: title,
                additionalInfo: additionalInfo,
                trailing: trailing,
              ),
            ),
          ),
        ),
      );

      final Offset foundInfo = tester.getTopLeft(find.text('Not Connected'));
      final Offset foundTrailing = tester.getTopRight(find.byType(CupertinoListTileChevron));

      expect(foundInfo.dx > foundTrailing.dx, isTrue);
    });
  });

  testWidgets('onTap with delay does not throw an exception', (WidgetTester tester) async {
    const Widget title = Text('CupertinoListTile');
    bool showTile = true;

    Future<void> onTap() async {
      showTile = false;
      await Future<void>.delayed(
        const Duration(seconds: 1),
        () => showTile = true,
      );
    }

    Widget buildCupertinoListTile() {
      return CupertinoApp(
        home: CupertinoPageScaffold(
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                if (showTile)
                  CupertinoListTile(
                    onTap: onTap,
                    title: title,
                  ),
               ],
            ),
          ),
        ),
      );
    }

    await tester.pumpWidget(buildCupertinoListTile());
    expect(showTile, isTrue);
    await tester.tap(find.byType(CupertinoListTile));
    expect(showTile, isFalse);
    await tester.pumpWidget(buildCupertinoListTile());
    await tester.pumpAndSettle(const Duration(seconds: 5));
    expect(tester.takeException(), null);
  });

  testWidgets('title does not overflow', (WidgetTester tester) async {
    await tester.pumpWidget(
      CupertinoApp(
        home: CupertinoPageScaffold(
          child: CupertinoListTile(
            title: Text('CupertinoListTile' * 10),
          ),
        ),
      ),
    );

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

  testWidgets('subtitle does not overflow', (WidgetTester tester) async {
    await tester.pumpWidget(
      CupertinoApp(
        home: CupertinoPageScaffold(
          child: CupertinoListTile(
            title: const Text(''),
            subtitle: Text('CupertinoListTile' * 10),
          ),
        ),
      ),
    );

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