// 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 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_test/flutter_test.dart';

import '../../driver_extension.dart';
import '../extension/wait_conditions.dart';
import 'diagnostics_tree.dart';
import 'error.dart';
import 'find.dart';
import 'frame_sync.dart';
import 'geometry.dart';
import 'gesture.dart';
import 'health.dart';
import 'layer_tree.dart';
import 'message.dart';
import 'render_tree.dart';
import 'request_data.dart';
import 'semantics.dart';
import 'text.dart';
import 'text_input_action.dart' show SendTextInputAction;
import 'wait.dart';

/// A factory which creates [Finder]s from [SerializableFinder]s.
mixin CreateFinderFactory {
  /// Creates the flutter widget finder from [SerializableFinder].
  Finder createFinder(SerializableFinder finder) {
    final String finderType = finder.finderType;
    switch (finderType) {
      case 'ByText':
        return _createByTextFinder(finder as ByText);
      case 'ByTooltipMessage':
        return _createByTooltipMessageFinder(finder as ByTooltipMessage);
      case 'BySemanticsLabel':
        return _createBySemanticsLabelFinder(finder as BySemanticsLabel);
      case 'ByValueKey':
        return _createByValueKeyFinder(finder as ByValueKey);
      case 'ByType':
        return _createByTypeFinder(finder as ByType);
      case 'PageBack':
        return _createPageBackFinder();
      case 'Ancestor':
        return _createAncestorFinder(finder as Ancestor);
      case 'Descendant':
        return _createDescendantFinder(finder as Descendant);
      default:
        throw DriverError('Unsupported search specification type $finderType');
    }
  }

  Finder _createByTextFinder(ByText arguments) {
    return find.text(arguments.text);
  }

  Finder _createByTooltipMessageFinder(ByTooltipMessage arguments) {
    return find.byElementPredicate((Element element) {
      final Widget widget = element.widget;
      if (widget is Tooltip) {
        return widget.message == arguments.text;
      }
      return false;
    }, description: 'widget with text tooltip "${arguments.text}"');
  }

  Finder _createBySemanticsLabelFinder(BySemanticsLabel arguments) {
    return find.byElementPredicate((Element element) {
      if (element is! RenderObjectElement) {
        return false;
      }
      final String? semanticsLabel = element.renderObject.debugSemantics?.label;
      if (semanticsLabel == null) {
        return false;
      }
      final Pattern label = arguments.label;
      return label is RegExp
          ? label.hasMatch(semanticsLabel)
          : label == semanticsLabel;
    }, description: 'widget with semantic label "${arguments.label}"');
  }

  Finder _createByValueKeyFinder(ByValueKey arguments) {
    switch (arguments.keyValueType) {
      case 'int':
        return find.byKey(ValueKey<int>(arguments.keyValue as int));
      case 'String':
        return find.byKey(ValueKey<String>(arguments.keyValue as String));
      default:
        throw UnimplementedError('Unsupported ByValueKey type: ${arguments.keyValueType}');
    }
  }

  Finder _createByTypeFinder(ByType arguments) {
    return find.byElementPredicate((Element element) {
      return element.widget.runtimeType.toString() == arguments.type;
    }, description: 'widget with runtimeType "${arguments.type}"');
  }

  Finder _createPageBackFinder() {
    return find.byElementPredicate((Element element) {
      final Widget widget = element.widget;
      if (widget is Tooltip) {
        return widget.message == 'Back';
      }
      if (widget is CupertinoNavigationBarBackButton) {
        return true;
      }
      return false;
    }, description: 'Material or Cupertino back button');
  }

  Finder _createAncestorFinder(Ancestor arguments) {
    final Finder finder = find.ancestor(
      of: createFinder(arguments.of),
      matching: createFinder(arguments.matching),
      matchRoot: arguments.matchRoot,
    );
    return arguments.firstMatchOnly ? finder.first : finder;
  }

  Finder _createDescendantFinder(Descendant arguments) {
    final Finder finder = find.descendant(
      of: createFinder(arguments.of),
      matching: createFinder(arguments.matching),
      matchRoot: arguments.matchRoot,
    );
    return arguments.firstMatchOnly ? finder.first : finder;
  }
}

/// A factory for [Command] handlers.
mixin CommandHandlerFactory {
  /// With [_frameSync] enabled, Flutter Driver will wait to perform an action
  /// until there are no pending frames in the app under test.
  bool _frameSync = true;

  /// Gets [DataHandler] for result delivery.
  @protected
  DataHandler? getDataHandler() => null;

  /// Registers text input emulation.
  @protected
  void registerTextInput() {
    _testTextInput.register();
  }

  final TestTextInput _testTextInput = TestTextInput();

  /// Deserializes the finder from JSON generated by [Command.serialize] or [CommandWithTarget.serialize].
  Future<Result> handleCommand(Command command, WidgetController prober, CreateFinderFactory finderFactory) {
    switch(command.kind) {
      case 'get_health': return _getHealth(command);
      case 'get_layer_tree': return _getLayerTree(command);
      case 'get_render_tree': return _getRenderTree(command);
      case 'enter_text': return _enterText(command);
      case 'send_text_input_action': return _sendTextInputAction(command);
      case 'get_text': return _getText(command, finderFactory);
      case 'request_data': return _requestData(command);
      case 'scroll': return _scroll(command, prober, finderFactory);
      case 'scrollIntoView': return _scrollIntoView(command, finderFactory);
      case 'set_frame_sync': return _setFrameSync(command);
      case 'set_semantics': return _setSemantics(command);
      case 'set_text_entry_emulation': return _setTextEntryEmulation(command);
      case 'tap': return _tap(command, prober, finderFactory);
      case 'waitFor': return _waitFor(command, finderFactory);
      case 'waitForAbsent': return _waitForAbsent(command, finderFactory);
      case 'waitForTappable': return _waitForTappable(command, finderFactory);
      case 'waitForCondition': return _waitForCondition(command);
      case 'waitUntilNoTransientCallbacks': return _waitUntilNoTransientCallbacks(command);
      case 'waitUntilNoPendingFrame': return _waitUntilNoPendingFrame(command);
      case 'waitUntilFirstFrameRasterized': return _waitUntilFirstFrameRasterized(command);
      case 'get_semantics_id': return _getSemanticsId(command, finderFactory);
      case 'get_offset': return _getOffset(command, finderFactory);
      case 'get_diagnostics_tree': return _getDiagnosticsTree(command, finderFactory);
    }

    throw DriverError('Unsupported command kind ${command.kind}');
  }

  Future<Health> _getHealth(Command command) async => const Health(HealthStatus.ok);

  Future<LayerTree> _getLayerTree(Command command) async {
    return LayerTree(RendererBinding.instance.renderView.debugLayer?.toStringDeep());
  }

  Future<RenderTree> _getRenderTree(Command command) async {
    return RenderTree(RendererBinding.instance.renderView.toStringDeep());
  }

  Future<Result> _enterText(Command command) async {
    if (!_testTextInput.isRegistered) {
      throw StateError(
        'Unable to fulfill `FlutterDriver.enterText`. Text emulation is '
        'disabled. You can enable it using `FlutterDriver.setTextEntryEmulation`.',
      );
    }
    final EnterText enterTextCommand = command as EnterText;
    _testTextInput.enterText(enterTextCommand.text);
    return Result.empty;
  }

  Future<Result> _sendTextInputAction(Command command) async {
    if (!_testTextInput.isRegistered) {
      throw StateError('Unable to fulfill `FlutterDriver.sendTextInputAction`. Text emulation is '
            'disabled. You can enable it using `FlutterDriver.setTextEntryEmulation`.');
    }
    final SendTextInputAction sendTextInputAction = command as SendTextInputAction;
    _testTextInput.receiveAction(TextInputAction.values[sendTextInputAction.textInputAction.index]);
    return Result.empty;
  }

  Future<RequestDataResult> _requestData(Command command) async {
    final RequestData requestDataCommand = command as RequestData;
    final DataHandler? dataHandler = getDataHandler();
    return RequestDataResult(dataHandler == null
      ? 'No requestData Extension registered'
      : await dataHandler(requestDataCommand.message));
  }

  Future<Result> _setFrameSync(Command command) async {
    final SetFrameSync setFrameSyncCommand = command as SetFrameSync;
    _frameSync = setFrameSyncCommand.enabled;
    return Result.empty;
  }

  Future<Result> _tap(Command command, WidgetController prober, CreateFinderFactory finderFactory) async {
    final Tap tapCommand = command as Tap;
    final Finder computedFinder = await waitForElement(
      finderFactory.createFinder(tapCommand.finder).hitTestable(),
    );
    await prober.tap(computedFinder);
    return Result.empty;
  }

  Future<Result> _waitFor(Command command, CreateFinderFactory finderFactory) async {
    final WaitFor waitForCommand = command as WaitFor;
    await waitForElement(finderFactory.createFinder(waitForCommand.finder));
    return Result.empty;
  }

  Future<Result> _waitForAbsent(Command command, CreateFinderFactory finderFactory) async {
    final WaitForAbsent waitForAbsentCommand = command as WaitForAbsent;
    await waitForAbsentElement(finderFactory.createFinder(waitForAbsentCommand.finder));
    return Result.empty;
  }

  Future<Result> _waitForTappable(Command command, CreateFinderFactory finderFactory) async {
    final WaitForTappable waitForTappableCommand = command as WaitForTappable;
    await waitForElement(
      finderFactory.createFinder(waitForTappableCommand.finder).hitTestable(),
    );
    return Result.empty;
  }

  Future<Result> _waitForCondition(Command command) async {
    final WaitForCondition waitForConditionCommand = command as WaitForCondition;
    final WaitCondition condition = deserializeCondition(waitForConditionCommand.condition);
    await condition.wait();
    return Result.empty;
  }

  @Deprecated(
    'This method has been deprecated in favor of _waitForCondition. '
    'This feature was deprecated after v1.9.3.'
  )
  Future<Result> _waitUntilNoTransientCallbacks(Command command) async {
    if (SchedulerBinding.instance.transientCallbackCount != 0) {
      await _waitUntilFrame(() => SchedulerBinding.instance.transientCallbackCount == 0);
    }
    return Result.empty;
  }

  /// Returns a future that waits until no pending frame is scheduled (frame is synced).
  ///
  /// Specifically, it checks:
  /// * Whether the count of transient callbacks is zero.
  /// * Whether there's no pending request for scheduling a new frame.
  ///
  /// We consider the frame is synced when both conditions are met.
  ///
  /// This method relies on a Flutter Driver mechanism called "frame sync",
  /// which waits for transient animations to finish. Persistent animations will
  /// cause this to wait forever.
  ///
  /// If a test needs to interact with the app while animations are running, it
  /// should avoid this method and instead disable the frame sync using
  /// `set_frame_sync` method. See [FlutterDriver.runUnsynchronized] for more
  /// details on how to do this. Note, disabling frame sync will require the
  /// test author to use some other method to avoid flakiness.
  ///
  /// This method has been deprecated in favor of [_waitForCondition].
  @Deprecated(
    'This method has been deprecated in favor of _waitForCondition. '
    'This feature was deprecated after v1.9.3.'
  )
  Future<Result> _waitUntilNoPendingFrame(Command command) async {
    await _waitUntilFrame(() {
      return SchedulerBinding.instance.transientCallbackCount == 0
          && !SchedulerBinding.instance.hasScheduledFrame;
    });
    return Result.empty;
  }

  Future<GetSemanticsIdResult> _getSemanticsId(Command command, CreateFinderFactory finderFactory) async {
    final GetSemanticsId semanticsCommand = command as GetSemanticsId;
    final Finder target = await waitForElement(finderFactory.createFinder(semanticsCommand.finder));
    final Iterable<Element> elements = target.evaluate();
    if (elements.length > 1) {
      throw StateError('Found more than one element with the same ID: $elements');
    }
    final Element element = elements.single;
    RenderObject? renderObject = element.renderObject;
    SemanticsNode? node;
    while (renderObject != null && node == null) {
      node = renderObject.debugSemantics;
      renderObject = renderObject.parent as RenderObject?;
    }
    if (node == null) {
      throw StateError('No semantics data found');
    }
    return GetSemanticsIdResult(node.id);
  }

  Future<GetOffsetResult> _getOffset(Command command, CreateFinderFactory finderFactory) async {
    final GetOffset getOffsetCommand = command as GetOffset;
    final Finder finder = await waitForElement(finderFactory.createFinder(getOffsetCommand.finder));
    final Element element = finder.evaluate().single;
    final RenderBox box = (element.renderObject as RenderBox?)!;
    Offset localPoint;
    switch (getOffsetCommand.offsetType) {
      case OffsetType.topLeft:
        localPoint = Offset.zero;
        break;
      case OffsetType.topRight:
        localPoint = box.size.topRight(Offset.zero);
        break;
      case OffsetType.bottomLeft:
        localPoint = box.size.bottomLeft(Offset.zero);
        break;
      case OffsetType.bottomRight:
        localPoint = box.size.bottomRight(Offset.zero);
        break;
      case OffsetType.center:
        localPoint = box.size.center(Offset.zero);
        break;
    }
    final Offset globalPoint = box.localToGlobal(localPoint);
    return GetOffsetResult(dx: globalPoint.dx, dy: globalPoint.dy);
  }

  Future<DiagnosticsTreeResult> _getDiagnosticsTree(Command command, CreateFinderFactory finderFactory) async {
    final GetDiagnosticsTree diagnosticsCommand = command as GetDiagnosticsTree;
    final Finder finder = await waitForElement(finderFactory.createFinder(diagnosticsCommand.finder));
    final Element element = finder.evaluate().single;
    DiagnosticsNode diagnosticsNode;
    switch (diagnosticsCommand.diagnosticsType) {
      case DiagnosticsType.renderObject:
        diagnosticsNode = element.renderObject!.toDiagnosticsNode();
        break;
      case DiagnosticsType.widget:
        diagnosticsNode = element.toDiagnosticsNode();
        break;
    }
    return DiagnosticsTreeResult(diagnosticsNode.toJsonMap(DiagnosticsSerializationDelegate(
      subtreeDepth: diagnosticsCommand.subtreeDepth,
      includeProperties: diagnosticsCommand.includeProperties,
    )));
  }

  Future<Result> _scroll(Command command, WidgetController prober, CreateFinderFactory finderFactory) async {
    final Scroll scrollCommand = command as Scroll;
    final Finder target = await waitForElement(finderFactory.createFinder(scrollCommand.finder));
    final int totalMoves = scrollCommand.duration.inMicroseconds * scrollCommand.frequency ~/ Duration.microsecondsPerSecond;
    final Offset delta = Offset(scrollCommand.dx, scrollCommand.dy) / totalMoves.toDouble();
    final Duration pause = scrollCommand.duration ~/ totalMoves;
    final Offset startLocation = prober.getCenter(target);
    Offset currentLocation = startLocation;
    final TestPointer pointer = TestPointer();
    prober.binding.handlePointerEvent(pointer.down(startLocation));
    await Future<void>.value(); // so that down and move don't happen in the same microtask
    for (int moves = 0; moves < totalMoves; moves += 1) {
      currentLocation = currentLocation + delta;
      prober.binding.handlePointerEvent(pointer.move(currentLocation));
      await Future<void>.delayed(pause);
    }
    prober.binding.handlePointerEvent(pointer.up());

    return Result.empty;
  }

  Future<Result> _scrollIntoView(Command command, CreateFinderFactory finderFactory) async {
    final ScrollIntoView scrollIntoViewCommand = command as ScrollIntoView;
    final Finder target = await waitForElement(finderFactory.createFinder(scrollIntoViewCommand.finder));
    await Scrollable.ensureVisible(target.evaluate().single, duration: const Duration(milliseconds: 100), alignment: scrollIntoViewCommand.alignment);
    return Result.empty;
  }

  Future<GetTextResult> _getText(Command command, CreateFinderFactory finderFactory) async {
    final GetText getTextCommand = command as GetText;
    final Finder target = await waitForElement(finderFactory.createFinder(getTextCommand.finder));

    final Widget widget = target.evaluate().single.widget;
    String? text;

    if (widget.runtimeType == Text) {
      text = (widget as Text).data;
    } else if (widget.runtimeType == RichText) {
      final RichText richText = widget as RichText;
      text = richText.text.toPlainText(
        includeSemanticsLabels: false,
        includePlaceholders: false,
      );
    } else if (widget.runtimeType == TextField) {
      text = (widget as TextField).controller?.text;
    } else if (widget.runtimeType == TextFormField) {
      text = (widget as TextFormField).controller?.text;
    } else if (widget.runtimeType == EditableText) {
      text = (widget as EditableText).controller.text;
    }

    if (text == null) {
      throw UnsupportedError('Type ${widget.runtimeType} is currently not supported by getText');
    }

    return GetTextResult(text);
  }

  Future<Result> _setTextEntryEmulation(Command command) async {
    final SetTextEntryEmulation setTextEntryEmulationCommand = command as SetTextEntryEmulation;
    if (setTextEntryEmulationCommand.enabled) {
      _testTextInput.register();
    } else {
      _testTextInput.unregister();
    }
    return Result.empty;
  }

  SemanticsHandle? _semantics;
  bool get _semanticsIsEnabled => RendererBinding.instance.pipelineOwner.semanticsOwner != null;

  Future<SetSemanticsResult> _setSemantics(Command command) async {
    final SetSemantics setSemanticsCommand = command as SetSemantics;
    final bool semanticsWasEnabled = _semanticsIsEnabled;
    if (setSemanticsCommand.enabled && _semantics == null) {
      _semantics = RendererBinding.instance.pipelineOwner.ensureSemantics();
      if (!semanticsWasEnabled) {
        // wait for the first frame where semantics is enabled.
        final Completer<void> completer = Completer<void>();
        SchedulerBinding.instance.addPostFrameCallback((Duration d) {
          completer.complete();
        });
        await completer.future;
      }
    } else if (!setSemanticsCommand.enabled && _semantics != null) {
      _semantics!.dispose();
      _semantics = null;
    }
    return SetSemanticsResult(semanticsWasEnabled != _semanticsIsEnabled);
  }

  // This can be used to wait for the first frame being rasterized during app launch.
  @Deprecated(
    'This method has been deprecated in favor of _waitForCondition. '
    'This feature was deprecated after v1.9.3.'
  )
  Future<Result> _waitUntilFirstFrameRasterized(Command command) async {
    await WidgetsBinding.instance.waitUntilFirstFrameRasterized;
    return Result.empty;
  }

  /// Runs `finder` repeatedly until it finds one or more [Element]s.
  Future<Finder> waitForElement(Finder finder) async {
    if (_frameSync) {
      await _waitUntilFrame(() => SchedulerBinding.instance.transientCallbackCount == 0);
    }

    await _waitUntilFrame(() => finder.evaluate().isNotEmpty);

    if (_frameSync) {
      await _waitUntilFrame(() => SchedulerBinding.instance.transientCallbackCount == 0);
    }

    return finder;
  }

  /// Runs `finder` repeatedly until it finds zero [Element]s.
  Future<Finder> waitForAbsentElement(Finder finder) async {
    if (_frameSync) {
      await _waitUntilFrame(() => SchedulerBinding.instance.transientCallbackCount == 0);
    }

    await _waitUntilFrame(() => finder.evaluate().isEmpty);

    if (_frameSync) {
      await _waitUntilFrame(() => SchedulerBinding.instance.transientCallbackCount == 0);
    }

    return finder;
  }

  // Waits until at the end of a frame the provided [condition] is [true].
  Future<void> _waitUntilFrame(bool Function() condition, [ Completer<void>? completer ]) {
    completer ??= Completer<void>();
    if (!condition()) {
      SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
        _waitUntilFrame(condition, completer);
      });
    } else {
      completer.complete();
    }
    return completer.future;
  }
}
