// Copyright 2013 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.

package com.example.android_unit_tests;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import com.example.android_unit_tests.AllDatatypes.*;
import io.flutter.plugin.common.BinaryMessenger;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;

public class AllDatatypesTest {
  @Test
  public void nullValues() {
    Everything everything = new Everything();
    BinaryMessenger binaryMessenger = mock(BinaryMessenger.class);
    doAnswer(
            invocation -> {
              ByteBuffer message = invocation.getArgument(1);
              BinaryMessenger.BinaryReply reply = invocation.getArgument(2);
              message.position(0);
              ArrayList<Object> args =
                  (ArrayList<Object>) FlutterEverything.getCodec().decodeMessage(message);
              ByteBuffer replyData = FlutterEverything.getCodec().encodeMessage(args.get(0));
              replyData.position(0);
              reply.reply(replyData);
              return null;
            })
        .when(binaryMessenger)
        .send(anyString(), any(), any());
    FlutterEverything api = new FlutterEverything(binaryMessenger);
    boolean[] didCall = {false};
    api.echo(
        everything,
        (result) -> {
          didCall[0] = true;
          assertNull(everything.getABool());
          assertNull(everything.getAnInt());
          assertNull(everything.getADouble());
          assertNull(everything.getAString());
          assertNull(everything.getAByteArray());
          assertNull(everything.getA4ByteArray());
          assertNull(everything.getA8ByteArray());
          assertNull(everything.getAFloatArray());
          assertNull(everything.getAList());
          assertNull(everything.getAMap());
        });
    assertTrue(didCall[0]);
  }

  private static HashMap<Object, Object> makeMap(String key, Integer value) {
    HashMap<Object, Object> result = new HashMap<Object, Object>();
    result.put(key, value);
    return result;
  }

  private static boolean floatArraysEqual(double[] x, double[] y) {
    if (x.length != y.length) {
      return false;
    }
    for (int i = 0; i < x.length; ++i) {
      if (x[i] != y[i]) {
        return false;
      }
    }
    return true;
  }

  @Test
  public void hasValues() {
    Everything everything = new Everything();
    everything.setABool(false);
    everything.setAnInt(1234L);
    everything.setADouble(2.0);
    everything.setAString("hello");
    everything.setAByteArray(new byte[] {1, 2, 3, 4});
    everything.setA4ByteArray(new int[] {1, 2, 3, 4});
    everything.setA8ByteArray(new long[] {1, 2, 3, 4});
    everything.setAFloatArray(new double[] {0.5, 0.25, 1.5, 1.25});
    everything.setAList(Arrays.asList(new int[] {1, 2, 3}));
    everything.setAMap(makeMap("hello", 1234));
    BinaryMessenger binaryMessenger = mock(BinaryMessenger.class);
    doAnswer(
            invocation -> {
              ByteBuffer message = invocation.getArgument(1);
              BinaryMessenger.BinaryReply reply = invocation.getArgument(2);
              message.position(0);
              ArrayList<Object> args =
                  (ArrayList<Object>) FlutterEverything.getCodec().decodeMessage(message);
              ByteBuffer replyData = FlutterEverything.getCodec().encodeMessage(args.get(0));
              replyData.position(0);
              reply.reply(replyData);
              return null;
            })
        .when(binaryMessenger)
        .send(anyString(), any(), any());
    FlutterEverything api = new FlutterEverything(binaryMessenger);
    boolean[] didCall = {false};
    api.echo(
        everything,
        (result) -> {
          didCall[0] = true;
          assertEquals(everything.getABool(), result.getABool());
          assertEquals(everything.getAnInt(), result.getAnInt());
          assertEquals(everything.getADouble(), result.getADouble());
          assertEquals(everything.getAString(), result.getAString());
          assertArrayEquals(everything.getAByteArray(), result.getAByteArray());
          assertArrayEquals(everything.getA4ByteArray(), result.getA4ByteArray());
          assertArrayEquals(everything.getA8ByteArray(), result.getA8ByteArray());
          assertTrue(floatArraysEqual(everything.getAFloatArray(), result.getAFloatArray()));
          assertArrayEquals(everything.getAList().toArray(), result.getAList().toArray());
          assertArrayEquals(
              everything.getAMap().keySet().toArray(), result.getAMap().keySet().toArray());
          assertArrayEquals(
              everything.getAMap().values().toArray(), result.getAMap().values().toArray());
        });
    assertTrue(didCall[0]);
  }

  @Test
  public void integerToLong() {
    Everything everything = new Everything();
    everything.setAnInt(123L);
    Map<String, Object> map = everything.toMap();
    assertTrue(map.containsKey("anInt"));
    map.put("anInt", 123);
    Everything readEverything = Everything.fromMap(map);
    assertEquals(readEverything.getAnInt(), everything.getAnInt());
  }
}
