// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.bot.builder.teams;

import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.microsoft.bot.builder.BotAdapter;
import com.microsoft.bot.builder.BotFrameworkAdapter;
import com.microsoft.bot.builder.InvokeResponse;
import com.microsoft.bot.builder.SimpleAdapter;
import com.microsoft.bot.builder.TurnContext;
import com.microsoft.bot.builder.TurnContextImpl;
import com.microsoft.bot.connector.Channels;
import com.microsoft.bot.connector.ConnectorClient;
import com.microsoft.bot.connector.Conversations;
import com.microsoft.bot.connector.authentication.AppCredentials;
import com.microsoft.bot.connector.authentication.MicrosoftAppCredentials;
import com.microsoft.bot.restclient.serializer.JacksonAdapter;
import com.microsoft.bot.schema.Activity;
import com.microsoft.bot.schema.ActivityTypes;
import com.microsoft.bot.schema.ChannelAccount;
import com.microsoft.bot.schema.ConversationAccount;
import com.microsoft.bot.schema.ConversationParameters;
import com.microsoft.bot.schema.ConversationReference;
import com.microsoft.bot.schema.ConversationResourceResponse;
import com.microsoft.bot.schema.ResourceResponse;
import com.microsoft.bot.schema.Serialization;
import com.microsoft.bot.schema.teams.AppBasedLinkQuery;
import com.microsoft.bot.schema.teams.ChannelInfo;
import com.microsoft.bot.schema.teams.FileConsentCardResponse;
import com.microsoft.bot.schema.teams.FileUploadInfo;
import com.microsoft.bot.schema.teams.MeetingEndEventDetails;
import com.microsoft.bot.schema.teams.MeetingStartEventDetails;
import com.microsoft.bot.schema.teams.MessagingExtensionAction;
import com.microsoft.bot.schema.teams.MessagingExtensionActionResponse;
import com.microsoft.bot.schema.teams.MessagingExtensionQuery;
import com.microsoft.bot.schema.teams.MessagingExtensionResponse;
import com.microsoft.bot.schema.teams.O365ConnectorCardActionQuery;
import com.microsoft.bot.schema.teams.TaskModuleRequest;
import com.microsoft.bot.schema.teams.TaskModuleRequestContext;
import com.microsoft.bot.schema.teams.TaskModuleResponse;
import com.microsoft.bot.schema.teams.TeamInfo;
import com.microsoft.bot.schema.teams.TeamsChannelAccount;
import com.microsoft.bot.schema.teams.TeamsChannelData;
import java.io.IOException;
import org.apache.commons.lang3.NotImplementedException;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

public class TeamsActivityHandlerTests {
    @Test
    public void TestConversationUpdateBotTeamsMemberAdded() {
        String baseUri = "https://test.coffee";
        ConnectorClient connectorClient = getConnectorClient(
            "http://localhost/",
            MicrosoftAppCredentials.empty()
        );

        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        ArrayList<ChannelAccount> members = new ArrayList<ChannelAccount>();
        members.add(new ChannelAccount("botid-1"));
        activity.setMembersAdded(members);
        activity.setRecipient(new ChannelAccount("botid-1"));
        TeamsChannelData channelData = new TeamsChannelData();
        channelData.setEventType("teamMemberAdded");
        channelData.setTeam(new TeamInfo("team-id"));
        activity.setChannelData(channelData);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new SimpleAdapter(), activity);
        turnContext.getTurnState().add(BotFrameworkAdapter.CONNECTOR_CLIENT_KEY, connectorClient);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMembersAdded", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsMemberAdded() {
        String baseUri = "https://test.coffee";
        ConnectorClient connectorClient = getConnectorClient(
            "http://localhost/",
            MicrosoftAppCredentials.empty()
        );

        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        ArrayList<ChannelAccount> members = new ArrayList<ChannelAccount>();
        members.add(new ChannelAccount("id-1"));
        activity.setMembersAdded(members);
        activity.setRecipient(new ChannelAccount("b"));
        TeamsChannelData channelData = new TeamsChannelData();
        channelData.setEventType("teamMemberAdded");
        channelData.setTeam(new TeamInfo("team-id"));
        activity.setChannelData(channelData);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new SimpleAdapter(), activity);
        turnContext.getTurnState().add(BotFrameworkAdapter.CONNECTOR_CLIENT_KEY, connectorClient);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMembersAdded", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsMemberAddedNoTeam() {
        String baseUri = "https://test.coffee";
        ConnectorClient connectorClient = getConnectorClient(
            "http://localhost/",
            MicrosoftAppCredentials.empty()
        );

        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        ArrayList<ChannelAccount> members = new ArrayList<ChannelAccount>();
        members.add(new ChannelAccount("id-1"));
        activity.setMembersAdded(members);
        activity.setRecipient(new ChannelAccount("b"));
        activity.setConversation(new ConversationAccount("conversation-id"));
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new SimpleAdapter(), activity);
        turnContext.getTurnState().add(BotFrameworkAdapter.CONNECTOR_CLIENT_KEY, connectorClient);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMembersAdded", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsMemberAddedFullDetailsInEvent() {
        String baseUri = "https://test.coffee";
        ConnectorClient connectorClient = getConnectorClient(
            "http://localhost/",
            MicrosoftAppCredentials.empty()
        );

        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        ArrayList<ChannelAccount> members = new ArrayList<ChannelAccount>();
        TeamsChannelAccount teams = new TeamsChannelAccount();
        teams.setId("id-1");
        teams.setName("name-1");
        teams.setAadObjectId("aadobject-1");
        teams.setEmail("test@microsoft.com");
        teams.setGivenName("given-1");
        teams.setSurname("surname-1");
        teams.setUserPrincipalName("t@microsoft.com");
        teams.setTenantId("testTenantId");
        teams.setUserRole("guest");
        members.add(teams);
        activity.setMembersAdded(members);
        activity.setRecipient(new ChannelAccount("b"));
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("teamMemberAdded");
        data.setTeam(new TeamInfo("team-id"));
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        // serialize to json and back to verify we can get back to the
        // correct Activity. i.e., In this case, mainly the TeamsChannelAccount.
        try {
            JacksonAdapter jacksonAdapter = new JacksonAdapter();
            String json = jacksonAdapter.serialize(activity);
            activity = jacksonAdapter.deserialize(json, Activity.class);
        } catch (Throwable t) {
            Assert.fail("Should not have thrown in serialization test.");
        }

        TurnContext turnContext = new TurnContextImpl(new SimpleAdapter(), activity);
        turnContext.getTurnState().add(BotFrameworkAdapter.CONNECTOR_CLIENT_KEY, connectorClient);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMembersAdded", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsMemberRemoved() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        ArrayList<ChannelAccount> members = new ArrayList<ChannelAccount>();
        members.add(new ChannelAccount("a"));
        activity.setMembersRemoved(members);
        activity.setRecipient(new ChannelAccount("b"));
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("teamMemberRemoved");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMembersRemoved", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsChannelCreated() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("channelCreated");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsChannelCreated", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsChannelDeleted() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("channelDeleted");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsChannelDeleted", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsChannelRenamed() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("channelRenamed");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsChannelRenamed", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsChannelRestored() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("channelRestored");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsChannelRestored", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsTeamRenamed() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("teamRenamed");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsTeamRenamed", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsTeamArchived() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("teamArchived");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsTeamArchived", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsTeamDeleted() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("teamDeleted");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsTeamDeleted", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsTeamHardDeleted() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("teamHardDeleted");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsTeamHardDeleted", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsTeamRestored() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("teamRestored");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsTeamRestored", bot.record.get(1));
    }

    @Test
    public void TestConversationUpdateTeamsTeamUnarchived() {
        Activity activity = new Activity(ActivityTypes.CONVERSATION_UPDATE);
        TeamsChannelData data = new TeamsChannelData();
        data.setEventType("teamUnarchived");
        activity.setChannelData(data);
        activity.setChannelId(Channels.MSTEAMS);

        TurnContext turnContext = new TurnContextImpl(new NotImplementedAdapter(), activity);

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onConversationUpdateActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsTeamUnarchived", bot.record.get(1));
    }

    @Test
    public void TestFileConsentAccept() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("fileConsent/invoke");
        FileUploadInfo fileInfo = new FileUploadInfo();
        fileInfo.setUniqueId("uniqueId");
        fileInfo.setFileType("fileType");
        fileInfo.setUploadUrl("uploadUrl");
        FileConsentCardResponse response = new FileConsentCardResponse();
        response.setAction("accept");
        response.setUploadInfo(fileInfo);
        activity.setValue(response);

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(3, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsFileConsent", bot.record.get(1));
        Assert.assertEquals("onTeamsFileConsentAccept", bot.record.get(2));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestFileConsentDecline() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("fileConsent/invoke");
        FileUploadInfo fileInfo = new FileUploadInfo();
        fileInfo.setUniqueId("uniqueId");
        fileInfo.setFileType("fileType");
        fileInfo.setUploadUrl("uploadUrl");
        FileConsentCardResponse response = new FileConsentCardResponse();
        response.setAction("decline");
        response.setUploadInfo(fileInfo);
        activity.setValue(response);

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(3, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsFileConsent", bot.record.get(1));
        Assert.assertEquals("onTeamsFileConsentDecline", bot.record.get(2));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestActionableMessageExecuteAction() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("actionableMessage/executeAction");
        activity.setValue(new O365ConnectorCardActionQuery());

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsO365ConnectorCardAction", bot.record.get(1));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestComposeExtensionQueryLink() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("composeExtension/queryLink");
        activity.setValue(new AppBasedLinkQuery());

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsAppBasedLinkQuery", bot.record.get(1));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestComposeExtensionQuery() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("composeExtension/query");
        activity.setValue(new MessagingExtensionQuery());

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMessagingExtensionQuery", bot.record.get(1));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestMessagingExtensionSelectItemAsync() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("composeExtension/selectItem");
        activity.setValue(new MessagingExtensionQuery());

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMessagingExtensionSelectItem", bot.record.get(1));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestMessagingExtensionSubmitAction() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("composeExtension/submitAction");
        activity.setValue(new MessagingExtensionQuery());

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(3, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMessagingExtensionSubmitActionDispatch", bot.record.get(1));
        Assert.assertEquals("onTeamsMessagingExtensionSubmitAction", bot.record.get(2));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestMessagingExtensionSubmitActionPreviewActionEdit() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("composeExtension/submitAction");
        MessagingExtensionAction action = new MessagingExtensionAction();
        action.setBotMessagePreviewAction("edit");
        activity.setValue(action);

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(3, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMessagingExtensionSubmitActionDispatch", bot.record.get(1));
        Assert.assertEquals("onTeamsMessagingExtensionBotMessagePreviewEdit", bot.record.get(2));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestMessagingExtensionSubmitActionPreviewActionSend() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("composeExtension/submitAction");
        MessagingExtensionAction action = new MessagingExtensionAction();
        action.setBotMessagePreviewAction("send");
        activity.setValue(action);

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(3, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMessagingExtensionSubmitActionDispatch", bot.record.get(1));
        Assert.assertEquals("onTeamsMessagingExtensionBotMessagePreviewSend", bot.record.get(2));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestMessagingExtensionFetchTask() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("composeExtension/fetchTask");
        MessagingExtensionAction action = new MessagingExtensionAction();
        action.setCommandId("testCommand");
        activity.setValue(action);

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMessagingExtensionFetchTask", bot.record.get(1));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestMessagingExtensionConfigurationQuerySettingUrl() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("composeExtension/querySettingUrl");
        MessagingExtensionAction action = new MessagingExtensionAction();
        action.setCommandId("testCommand");
        activity.setValue(action);

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals(
            "onTeamsMessagingExtensionConfigurationQuerySettingUrl",
            bot.record.get(1)
        );
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestMessagingExtensionConfigurationSetting() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("composeExtension/setting");
        MessagingExtensionAction action = new MessagingExtensionAction();
        action.setCommandId("testCommand");
        activity.setValue(action);

        AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();

        TurnContext turnContext = new TurnContextImpl(
            new SimpleAdapter(activitiesToSend::set),
            activity
        );

        TestActivityHandler bot = new TestActivityHandler();
        bot.onTurn(turnContext).join();

        Assert.assertEquals(2, bot.record.size());
        Assert.assertEquals("onInvokeActivity", bot.record.get(0));
        Assert.assertEquals("onTeamsMessagingExtensionConfigurationSetting", bot.record.get(1));
        Assert.assertNotNull(activitiesToSend.get());
        Assert.assertEquals(1, activitiesToSend.get().size());
        Assert.assertTrue(activitiesToSend.get().get(0).getValue() instanceof InvokeResponse);
        Assert.assertEquals(
            200,
            ((InvokeResponse) activitiesToSend.get().get(0).getValue()).getStatus()
        );
    }

    @Test
    public void TestTaskModuleFetch() {
        Activity activity = new Activity(ActivityTypes.INVOKE);
        activity.setName("task/fetch");
        TaskModuleRequestContext context = new TaskModuleRequestContext();
        context.setTheme("default");
