/*
 * Copyright 2019 Fitbit, Inc. All rights reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package com.fitbit.bluetooth.fbgatt;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;

import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.content.Context;
import android.os.Looper;
import androidx.test.core.app.ApplicationProvider;
import com.fitbit.bluetooth.fbgatt.tx.mocks.SubscribeToCharacteristicNotificationsMockTransaction;
import com.fitbit.bluetooth.fbgatt.tx.mocks.UnSubscribeToGattCharacteristicNotificationsMockTransaction;
import com.fitbit.bluetooth.fbgatt.util.LooperWatchdog;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(minSdk = 21)
public class GattNotifyIndicateTest {
  private GattConnection conn;
  private FitbitBluetoothDevice device;

  @Before
  public void before() {
    Context context = ApplicationProvider.getApplicationContext();
    BitGattDependencyProvider dependencyProviderSpy = spy(new BitGattDependencyProvider());
    doReturn(mock(PeripheralScanner.class))
        .when(dependencyProviderSpy)
        .getNewPeripheralScanner(any(), any());
    Looper mainLooper = context.getMainLooper();
    device = mock(FitbitBluetoothDevice.class);
    conn = spy(new GattConnection(device, mainLooper));
    conn.setMockMode(true);
    FitbitGatt.getInstance().putConnectionIntoDevices(device, conn);
    FitbitGatt.getInstance().startGattClient(context);
  }

  @Test
  public void subscribeToNotificationTest() {
    final byte[] fakeData = new byte[] {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
    BluetoothGattCharacteristic characteristic =
        new BluetoothGattCharacteristic(
            UUID.randomUUID(),
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattDescriptor.PERMISSION_READ
                | BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED);
    SubscribeToCharacteristicNotificationsMockTransaction subscribeChar =
        new SubscribeToCharacteristicNotificationsMockTransaction(
            conn,
            GattState.ENABLE_CHARACTERISTIC_NOTIFICATION_SUCCESS,
            characteristic,
            fakeData,
            false);
    conn.runTx(
        subscribeChar,
        result -> {
          assert (result.resultStatus.equals(TransactionResult.TransactionResultStatus.SUCCESS)
              && result.resultState.equals(subscribeChar.getSuccessState()));
        });
  }

  @Test
  public void unSubscribeToNotificationTest() {
    final byte[] fakeData = new byte[] {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
    BluetoothGattCharacteristic characteristic =
        new BluetoothGattCharacteristic(
            UUID.randomUUID(),
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattDescriptor.PERMISSION_READ
                | BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED);
    UnSubscribeToGattCharacteristicNotificationsMockTransaction unSubscribeChar =
        new UnSubscribeToGattCharacteristicNotificationsMockTransaction(
            conn,
            GattState.ENABLE_CHARACTERISTIC_NOTIFICATION_SUCCESS,
            characteristic,
            fakeData,
            false);
    conn.runTx(
        unSubscribeChar,
        result -> {
          assert (result.resultStatus.equals(TransactionResult.TransactionResultStatus.SUCCESS)
              && result.resultState.equals(unSubscribeChar.getSuccessState()));
        });
  }

  @Test
  public void failToSubscribeToNotificationTest() {
    final byte[] fakeData = new byte[] {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
    BluetoothGattCharacteristic characteristic =
        new BluetoothGattCharacteristic(
            UUID.randomUUID(),
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattDescriptor.PERMISSION_READ
                | BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED);
    SubscribeToCharacteristicNotificationsMockTransaction subscribeChar =
        new SubscribeToCharacteristicNotificationsMockTransaction(
            conn,
            GattState.ENABLE_CHARACTERISTIC_NOTIFICATION_SUCCESS,
            characteristic,
            fakeData,
            true);
    conn.runTx(
        subscribeChar,
        result -> {
          assert (result.resultStatus.equals(TransactionResult.TransactionResultStatus.TIMEOUT));
        });
  }

  @Test
  public void failToUnSubscribeToNotificationTest() {
    final byte[] fakeData = new byte[] {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
    BluetoothGattCharacteristic characteristic =
        new BluetoothGattCharacteristic(
            UUID.randomUUID(),
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattDescriptor.PERMISSION_READ
                | BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED);
    UnSubscribeToGattCharacteristicNotificationsMockTransaction unSubscribeChar =
        new UnSubscribeToGattCharacteristicNotificationsMockTransaction(
            conn,
            GattState.ENABLE_CHARACTERISTIC_NOTIFICATION_SUCCESS,
            characteristic,
            fakeData,
            true);
    conn.runTx(
        unSubscribeChar,
        result -> {
          assert (result.resultStatus.equals(TransactionResult.TransactionResultStatus.TIMEOUT));
        });
  }
}

@@ -1133,16 +1133,61 @@
 .Config;
+%0Aimport org.robolectric.shadows.ShadowLooper;
 %0A%0A@RunWi
@@ -1696,23 +1696,22 @@
 ooper = 
-context
+Looper
 .getMain

Change the way we fetch the looper