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

import '../widgets/clipboard_utils.dart';
import '../widgets/live_text_utils.dart';

void main() {
  final MockClipboard mockClipboard = MockClipboard();

  setUp(() async {
    TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
      SystemChannels.platform,
      mockClipboard.handleMethodCall,
    );
    // Fill the clipboard so that the Paste option is available in the text
    // selection menu.
    await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
  });

  tearDown(() {
    TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
      SystemChannels.platform,
      null,
    );
  });

  Finder findOverflowNextButton() {
    return find.byWidgetPredicate((Widget widget) =>
      widget is CustomPaint &&
          '${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter',
      );
  }

  testWidgetsWithLeakTracking('Builds the right toolbar on each platform, including web, and shows buttonItems', (WidgetTester tester) async {
    const String buttonText = 'Click me';

    await tester.pumpWidget(
      CupertinoApp(
        home: Center(
          child: CupertinoAdaptiveTextSelectionToolbar.buttonItems(
            anchors: const TextSelectionToolbarAnchors(
              primaryAnchor: Offset.zero,
            ),
            buttonItems: <ContextMenuButtonItem>[
              ContextMenuButtonItem(
                label: buttonText,
                onPressed: () {
                },
              ),
            ],
          ),
        ),
      ),
    );

    expect(find.text(buttonText), findsOneWidget);

    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
      case TargetPlatform.fuchsia:
      case TargetPlatform.iOS:
        expect(find.byType(CupertinoTextSelectionToolbar), findsOneWidget);
        expect(find.byType(CupertinoDesktopTextSelectionToolbar), findsNothing);
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
      case TargetPlatform.windows:
        expect(find.byType(CupertinoTextSelectionToolbar), findsNothing);
        expect(find.byType(CupertinoDesktopTextSelectionToolbar), findsOneWidget);
    }
  },
    variant: TargetPlatformVariant.all(),
    skip: isBrowser, // [intended] see https://github.com/flutter/flutter/issues/108382
  );

  testWidgetsWithLeakTracking('Can build children directly as well', (WidgetTester tester) async {
    final GlobalKey key = GlobalKey();

    await tester.pumpWidget(
      CupertinoApp(
        home: Center(
          child: CupertinoAdaptiveTextSelectionToolbar(
            anchors: const TextSelectionToolbarAnchors(
              primaryAnchor: Offset.zero,
            ),
            children: <Widget>[
              Container(key: key),
            ],
          ),
        ),
      ),
    );

    expect(find.byKey(key), findsOneWidget);
  },
    skip: isBrowser, // [intended] see https://github.com/flutter/flutter/issues/108382
  );

  testWidgetsWithLeakTracking('Can build from EditableTextState', (WidgetTester tester) async {
    final GlobalKey key = GlobalKey();
    final FocusNode focusNode = FocusNode();
    addTearDown(focusNode.dispose);
    final TextEditingController controller = TextEditingController();
    addTearDown(controller.dispose);
    await tester.pumpWidget(CupertinoApp(
      home: Align(
        alignment: Alignment.topLeft,
        child: SizedBox(
          width: 400,
          child: EditableText(
            controller: controller,
            backgroundCursorColor: const Color(0xff00ffff),
            focusNode: focusNode,
            style: const TextStyle(),
            cursorColor: const Color(0xff00ffff),
            selectionControls: cupertinoTextSelectionHandleControls,
            contextMenuBuilder: (
              BuildContext context,
              EditableTextState editableTextState,
            ) {
              return CupertinoAdaptiveTextSelectionToolbar.editableText(
                key: key,
                editableTextState: editableTextState,
              );
            },
          ),
        ),
      ),
    ));

    await tester.pump(); // Wait for autofocus to take effect.

    expect(find.byKey(key), findsNothing);

    // Long-press to bring up the context menu.
    final Finder textFinder = find.byType(EditableText);
    await tester.longPress(textFinder);
    tester.state<EditableTextState>(textFinder).showToolbar();
    await tester.pumpAndSettle();

    expect(find.byKey(key), findsOneWidget);
    expect(find.text('Copy'), findsNothing);
    expect(find.text('Cut'), findsNothing);
    expect(find.text('Select all'), findsNothing);
    expect(find.text('Paste'), findsOneWidget);

    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
      case TargetPlatform.fuchsia:
      case TargetPlatform.iOS:
        expect(find.byType(CupertinoTextSelectionToolbarButton), findsOneWidget);
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
      case TargetPlatform.windows:
        expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsOneWidget);
    }
  },
    skip: kIsWeb, // [intended] on web the browser handles the context menu.
    variant: TargetPlatformVariant.all(),
  );

  testWidgetsWithLeakTracking('Can build for editable text from raw parameters', (WidgetTester tester) async {
    final GlobalKey key = GlobalKey();
    await tester.pumpWidget(CupertinoApp(
      home: Center(
        child: CupertinoAdaptiveTextSelectionToolbar.editable(
          key: key,
          anchors: const TextSelectionToolbarAnchors(
            primaryAnchor: Offset.zero,
          ),
          clipboardStatus: ClipboardStatus.pasteable,
          onCopy: () {},
          onCut: () {},
          onPaste: () {},
          onSelectAll: () {},
          onLiveTextInput: () {},
          onLookUp: () {},
          onSearchWeb: () {},
          onShare: () {},
        ),
      ),
    ));

    expect(find.byKey(key), findsOneWidget);
    expect(find.text('Copy'), findsOneWidget);
    expect(find.text('Cut'), findsOneWidget);
    expect(find.text('Select All'), findsOneWidget);
    expect(find.text('Paste'), findsOneWidget);
    expect(find.text('Look Up'), findsOneWidget);

    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
        expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6));
      case TargetPlatform.fuchsia:
        expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6));
      case TargetPlatform.iOS:
        expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6));
        expect(findOverflowNextButton(), findsOneWidget);
        await tester.tapAt(tester.getCenter(findOverflowNextButton()));
        await tester.pumpAndSettle();
        expect(findLiveTextButton(), findsOneWidget);
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
      case TargetPlatform.windows:
        expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(8));
    }
  },
    skip: kIsWeb, // [intended] on web the browser handles the context menu.
    variant: TargetPlatformVariant.all(),
  );

  testWidgetsWithLeakTracking('Builds the correct button per-platform', (WidgetTester tester) async {
    const String buttonText = 'Click me';

    await tester.pumpWidget(
      CupertinoApp(
        home: Center(
          child: Builder(
            builder: (BuildContext context) {
              return Column(
                children: CupertinoAdaptiveTextSelectionToolbar.getAdaptiveButtons(
                  context,
                  <ContextMenuButtonItem>[
                    ContextMenuButtonItem(
                      label: buttonText,
                      onPressed: () {
                      },
                    ),
                  ],
                ).toList(),
              );
            },
          ),
        ),
      ),
    );

    expect(find.text(buttonText), findsOneWidget);

    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
      case TargetPlatform.fuchsia:
      case TargetPlatform.iOS:
        expect(find.byType(CupertinoTextSelectionToolbarButton), findsOneWidget);
        expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNothing);
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
      case TargetPlatform.windows:
        expect(find.byType(CupertinoTextSelectionToolbarButton), findsNothing);
        expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsOneWidget);
    }
  },
    variant: TargetPlatformVariant.all(),
  );
}