// 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 '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 'screenshot.dart';
import 'semantics.dart';
import 'text.dart';
import 'text_input_action.dart';
import 'wait.dart';

/// A factory for deserializing [SerializableFinder]s.
mixin DeserializeFinderFactory {
  /// Deserializes the finder from JSON generated by [SerializableFinder.serialize].
  ///
  /// The [path] is the current path to the [json] object from the parent object.
  SerializableFinder deserializeFinder(Map<String, String> json, {String? path}) {
    final String? finderType = json['finderType'];
    if (finderType == null) {
      throw ArgumentError.notNull(path == null ? 'finderType' : '$path.finderType');
    }
    return switch (finderType) {
      'ByType' => ByType.deserialize(json, path: path),
      'ByValueKey' => ByValueKey.deserialize(json, path: path),
      'ByTooltipMessage' => ByTooltipMessage.deserialize(json, path: path),
      'BySemanticsLabel' => BySemanticsLabel.deserialize(json, path: path),
      'ByText' => ByText.deserialize(json, path: path),
      'PageBack' => const PageBack(),
      'Descendant' => Descendant.deserialize(json, this, path: path),
      'Ancestor' => Ancestor.deserialize(json, this, path: path),
      _ => throw DriverError('Unsupported search specification type $finderType'),
    };
  }
}

/// A factory for deserializing [Command]s.
mixin DeserializeCommandFactory {
  /// Deserializes the finder from JSON generated by [Command.serialize] or [CommandWithTarget.serialize].
  ///
  /// The [path] is the current path to the [params] object from the parent object.
  Command deserializeCommand(
    Map<String, String> params,
    DeserializeFinderFactory finderFactory, {
    String? path,
  }) {
    final String? command = params['command'];
    if (command == null) {
      throw ArgumentError.notNull(path == null ? 'command' : '$path.command');
    }
    return switch (command) {
      'get_health' => GetHealth.deserialize(params),
      'get_layer_tree' => GetLayerTree.deserialize(params),
      'get_render_tree' => GetRenderTree.deserialize(params),
      'enter_text' => EnterText.deserialize(params, path: path),
      'send_text_input_action' => SendTextInputAction.deserialize(params),
      'get_text' => GetText.deserialize(params, finderFactory, path: path),
      'request_data' => RequestData.deserialize(params),
      'scroll' => Scroll.deserialize(params, finderFactory, path: path),
      'scrollIntoView' => ScrollIntoView.deserialize(params, finderFactory, path: path),
      'set_frame_sync' => SetFrameSync.deserialize(params),
      'set_semantics' => SetSemantics.deserialize(params),
      'set_text_entry_emulation' => SetTextEntryEmulation.deserialize(params),
      'tap' => Tap.deserialize(params, finderFactory, path: path),
      'waitFor' => WaitFor.deserialize(params, finderFactory, path: path),
      'waitForAbsent' => WaitForAbsent.deserialize(params, finderFactory, path: path),
      'waitForTappable' => WaitForTappable.deserialize(params, finderFactory, path: path),
      'waitForCondition' => WaitForCondition.deserialize(params),
      'waitUntilNoTransientCallbacks' => WaitForCondition.deserialize(params),
      'waitUntilNoPendingFrame' => WaitForCondition.deserialize(params),
      'waitUntilFirstFrameRasterized' => WaitForCondition.deserialize(params),
      'get_semantics_id' => GetSemanticsId.deserialize(params, finderFactory, path: path),
      'get_offset' => GetOffset.deserialize(params, finderFactory, path: path),
      'get_diagnostics_tree' => GetDiagnosticsTree.deserialize(params, finderFactory, path: path),
      'screenshot' => ScreenshotCommand.deserialize(params),
      final String? kind => throw DriverError('Unsupported command kind $kind'),
    };
  }
}
