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

import 'package:flutter/services.dart';

import 'pair.dart';
import 'test_step.dart';

class ExtendedStandardMessageCodec extends StandardMessageCodec {
  const ExtendedStandardMessageCodec();

  static const int _dateTime = 128;
  static const int _pair = 129;

  @override
  void writeValue(WriteBuffer buffer, dynamic value) {
    if (value is DateTime) {
      buffer.putUint8(_dateTime);
      buffer.putInt64(value.millisecondsSinceEpoch);
    } else if (value is Pair) {
      buffer.putUint8(_pair);
      writeValue(buffer, value.left);
      writeValue(buffer, value.right);
    } else {
      super.writeValue(buffer, value);
    }
  }

  @override
  dynamic readValueOfType(int type, ReadBuffer buffer) {
    switch (type) {
    case _dateTime:
      return DateTime.fromMillisecondsSinceEpoch(buffer.getInt64());
    case _pair:
      return Pair(readValue(buffer), readValue(buffer));
    default: return super.readValueOfType(type, buffer);
    }
  }
}

Future<TestStepResult> basicBinaryHandshake(ByteData? message) async {
  const BasicMessageChannel<ByteData?> channel =
      BasicMessageChannel<ByteData?>(
    'binary-msg',
    BinaryCodec(),
  );
  return _basicMessageHandshake<ByteData?>(
      'Binary >${toString(message)}<', channel, message);
}

Future<TestStepResult> basicStringHandshake(String? message) async {
  const BasicMessageChannel<String?> channel = BasicMessageChannel<String?>(
    'string-msg',
    StringCodec(),
  );
  return _basicMessageHandshake<String?>('String >$message<', channel, message);
}

Future<TestStepResult> basicJsonHandshake(dynamic message) async {
  const BasicMessageChannel<dynamic> channel =
      BasicMessageChannel<dynamic>(
    'json-msg',
    JSONMessageCodec(),
  );
  return _basicMessageHandshake<dynamic>('JSON >$message<', channel, message);
}

Future<TestStepResult> basicStandardHandshake(dynamic message) async {
  const BasicMessageChannel<dynamic> channel =
      BasicMessageChannel<dynamic>(
    'std-msg',
    ExtendedStandardMessageCodec(),
  );
  return _basicMessageHandshake<dynamic>(
      'Standard >${toString(message)}<', channel, message);
}

Future<void> _basicBackgroundStandardEchoMain(List<Object> args) async {
  final SendPort sendPort = args[2] as SendPort;
  final Object message = args[1];
  final String name = 'Background Echo >${toString(message)}<';
  const String description =
      'Uses a platform channel from a background isolate.';
  try {
    BackgroundIsolateBinaryMessenger.ensureInitialized(
        args[0] as RootIsolateToken);
    const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
      'std-echo',
      ExtendedStandardMessageCodec(),
    );
    final Object response = await channel.send(message) as Object;

    final TestStatus testStatus = TestStepResult.deepEquals(message, response)
        ? TestStatus.ok
        : TestStatus.failed;
    sendPort.send(TestStepResult(name, description, testStatus));
  } catch (ex) {
    sendPort.send(TestStepResult(name, description, TestStatus.failed,
        error: ex.toString()));
  }
}

Future<TestStepResult> basicBackgroundStandardEcho(Object message) async {
  final ReceivePort receivePort = ReceivePort();
  Isolate.spawn(_basicBackgroundStandardEchoMain, <Object>[
    ServicesBinding.rootIsolateToken!,
    message,
    receivePort.sendPort,
  ]);
  return await receivePort.first as TestStepResult;
}

Future<TestStepResult> basicBinaryMessageToUnknownChannel() async {
  const BasicMessageChannel<ByteData?> channel =
      BasicMessageChannel<ByteData?>(
    'binary-unknown',
    BinaryCodec(),
  );
  return _basicMessageToUnknownChannel<ByteData>('Binary', channel);
}

Future<TestStepResult> basicStringMessageToUnknownChannel() async {
  const BasicMessageChannel<String?> channel = BasicMessageChannel<String?>(
    'string-unknown',
    StringCodec(),
  );
  return _basicMessageToUnknownChannel<String>('String', channel);
}

Future<TestStepResult> basicJsonMessageToUnknownChannel() async {
  const BasicMessageChannel<dynamic> channel =
      BasicMessageChannel<dynamic>(
    'json-unknown',
    JSONMessageCodec(),
  );
  return _basicMessageToUnknownChannel<dynamic>('JSON', channel);
}

Future<TestStepResult> basicStandardMessageToUnknownChannel() async {
  const BasicMessageChannel<dynamic> channel =
      BasicMessageChannel<dynamic>(
    'std-unknown',
    ExtendedStandardMessageCodec(),
  );
  return _basicMessageToUnknownChannel<dynamic>('Standard', channel);
}

/// Sends the specified message to the platform, doing a
/// receive message/send reply/receive reply echo handshake initiated by the
/// platform, then expecting a reply echo to the original message.
///
/// Fails, if an error occurs, or if any message seen is not deeply equal to
/// the original message.
Future<TestStepResult> _basicMessageHandshake<T>(
  String description,
  BasicMessageChannel<T?> channel,
  T message,
) async {
  final List<dynamic> received = <dynamic>[];
  channel.setMessageHandler((T? message) async {
    received.add(message);
    return message;
  });
  dynamic messageEcho = nothing;
  dynamic error = nothing;
  try {
    messageEcho = await channel.send(message);
  } catch (e) {
    error = e;
  }
  return resultOfHandshake(
    'Basic message handshake',
    description,
    message,
    received,
    messageEcho,
    error,
  );
}

/// Sends a message on a channel that no one listens on.
Future<TestStepResult> _basicMessageToUnknownChannel<T>(
  String description,
  BasicMessageChannel<T?> channel,
) async {
  dynamic messageEcho = nothing;
  dynamic error = nothing;
  try {
    messageEcho = await channel.send(null);
  } catch (e) {
    error = e;
  }
  return resultOfHandshake(
    'Message on unknown channel',
    description,
    null,
    <dynamic>[null, null],
    messageEcho,
    error,
  );
}

String toString(dynamic message) {
  if (message is ByteData) {
    return message.buffer
        .asUint8List(message.offsetInBytes, message.lengthInBytes)
        .toString();
  } else {
    return '$message';
  }
}
