package com.google.sps.servlets;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceConfig;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.EmbeddedEntity;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Transaction;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseToken;
import com.google.firebase.auth.UserRecord;
import java.util.ArrayList;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class EndHelpTest {

  private final LocalServiceTestHelper helper =
      new LocalServiceTestHelper(
          // Use High Rep job policy to allow cross group transactions in tests.
          new LocalDatastoreServiceTestConfig().setApplyAllHighRepJobPolicy());

  private DatastoreService datastore;

  @Mock HttpServletRequest httpRequest;

  @Mock HttpServletResponse httpResponse;

  @Mock FirebaseAuth authInstance;

  @InjectMocks EndHelp finishStudent;

  @Before
  public void setUp() {
    helper.setUp();
    datastore = DatastoreServiceFactory.getDatastoreService();
    System.setProperty(
        DatastoreServiceConfig.DATASTORE_EMPTY_LIST_SUPPORT, Boolean.TRUE.toString());
  }

  @After
  public void tearDown() {
    // Clean up any dangling transactions.
    Transaction txn = datastore.getCurrentTransaction(null);
    if (txn != null && txn.isActive()) {
      txn.rollback();
    }

    helper.tearDown();
  }

  @Test
  public void doneHelping() throws Exception {
    Entity init = new Entity("Class");
    ArrayList<String> setQueue = new ArrayList<String>(Arrays.asList("uID1", "uID2"));

    init.setProperty("owner", "ownerID");
    init.setProperty("name", "testClass");
    init.setProperty("studentQueue", setQueue);

    EmbeddedEntity queueInfo = new EmbeddedEntity();
    queueInfo.setProperty("taID", "taID");
    queueInfo.setProperty("workspaceID", "workspaceID");

    EmbeddedEntity queueInfo2 = new EmbeddedEntity();
    queueInfo2.setProperty("taID", "ta3ID");
    queueInfo2.setProperty("workspaceID", "workspaceID");

    EmbeddedEntity beingHelped = new EmbeddedEntity();
    beingHelped.setProperty("test1", queueInfo);
    beingHelped.setProperty("test3", queueInfo2);

    init.setProperty("beingHelped", beingHelped);

    datastore.put(init);

    when(httpRequest.getParameter("taToken")).thenReturn("testID");
    FirebaseToken mockToken = mock(FirebaseToken.class);
    when(authInstance.verifyIdToken("testID")).thenReturn(mockToken);
    when(mockToken.getUid()).thenReturn("taID");

    when(httpRequest.getParameter("studentEmail")).thenReturn("test@google.com");

    when(httpRequest.getParameter("classCode")).thenReturn(KeyFactory.keyToString(init.getKey()));

    UserRecord mockUser = mock(UserRecord.class);
    when(authInstance.getUserByEmail("test@google.com")).thenReturn(mockUser);
    when(mockUser.getUid()).thenReturn("test1");

    finishStudent.doPost(httpRequest, httpResponse);

    Entity testClassEntity = datastore.prepare(new Query("Class")).asSingleEntity();

    ArrayList<String> testQueue = (ArrayList<String>) testClassEntity.getProperty("studentQueue");
    assertEquals(
        KeyFactory.keyToString(init.getKey()), KeyFactory.keyToString(testClassEntity.getKey()));
    assertEquals(2, testQueue.size());

    EmbeddedEntity got = (EmbeddedEntity) testClassEntity.getProperty("beingHelped");
    assertThat((EmbeddedEntity) got.getProperty("test1")).isNull();
    assertThat((EmbeddedEntity) got.getProperty("test3")).isNotNull();
  }
}

@@ -158,20 +158,204 @@
 ito.
-Mockito.mock
+ArgumentMatchers.anyString;%0Aimport static org.mockito.ArgumentMatchers.eq;%0Aimport static org.mockito.Mockito.mock;%0Aimport static org.mockito.Mockito.times;%0Aimport static org.mockito.Mockito.verify
 ;%0Aim
@@ -1154,16 +1154,109 @@
 Record;%0A
+import com.google.sps.tasks.TaskScheduler;%0Aimport com.google.sps.tasks.TaskSchedulerFactory;%0A
 import j
@@ -1300,16 +1300,54 @@
 Arrays;%0A
+import java.util.concurrent.TimeUnit;%0A
 import j
@@ -1983,16 +1983,60 @@
 tastore;
+%0A  private String QUEUE_NAME = %22QUEUE_NAME%22;
 %0A%0A  @Moc
@@ -2147,16 +2147,100 @@
 nstance;
+%0A  @Mock TaskSchedulerFactory taskSchedulerFactory;%0A  @Mock TaskScheduler scheduler;
 %0A%0A  @Inj
@@ -4206,24 +4206,155 @@
 (%22test1%22);%0A%0A
+    when(taskSchedulerFactory.create(anyString(), anyString())).thenReturn(scheduler);%0A    finishStudent.QUEUE_NAME = QUEUE_NAME;%0A%0A
     finishSt
@@ -4886,24 +4886,24 @@
 ).isNull();%0A
-
     assertTh
@@ -4960,15 +4960,201 @@
 tNull();
+%0A%0A    verify(taskSchedulerFactory, times(1)).create(eq(QUEUE_NAME), eq(%22/tasks/deleteEnv%22));%0A    verify(scheduler, times(1)).schedule(eq(%22workspaceID%22), eq(TimeUnit.HOURS.toSeconds(1)));
 %0A  %7D%0A%7D%0A

update EndHelpTest