package com.saranshmalik.rnzendeskchat;

import android.app.Activity;
import android.content.Context;

import android.graphics.Color;
import android.os.Build;
import androidx.core.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;

import java.lang.String;
import java.util.ArrayList;
import java.util.List;

import zendesk.chat.ChatMenuAction;
import javax.annotation.Nullable;
import zendesk.chat.Chat;
import zendesk.chat.ChatConfiguration;
import zendesk.chat.ChatEngine;
import zendesk.chat.ChatProvider;
import zendesk.chat.ChatSessionStatus;
import zendesk.chat.ChatState;
import zendesk.chat.ObservationScope;
import zendesk.chat.Observer;
import zendesk.chat.PreChatFormFieldStatus;
import zendesk.chat.ProfileProvider;
import zendesk.chat.PushNotificationsProvider;
import zendesk.chat.Providers;
import zendesk.chat.VisitorInfo;
import zendesk.chat.CompletionCallback;
import zendesk.core.JwtIdentity;
import zendesk.core.AnonymousIdentity;
import zendesk.core.Identity;
import zendesk.messaging.MessagingActivity;
import zendesk.messaging.MessagingConfiguration;
import zendesk.core.Zendesk;
import zendesk.support.Support;
import zendesk.support.guide.HelpCenterActivity;
import zendesk.support.guide.ViewArticleActivity;
import zendesk.support.requestlist.RequestListActivity;
import zendesk.answerbot.AnswerBot;
import zendesk.answerbot.AnswerBotEngine;
import zendesk.support.SupportEngine;

public class RNZendeskChat extends ReactContextBaseJavaModule {

  private ReactContext appContext;
  private static final String TAG = "ZendeskChat";
  private boolean isVisitorInfoSet = false;
  private VisitorInfo builtVisitorInfo = null;

  public RNZendeskChat(ReactApplicationContext reactContext) {
        super(reactContext);
        appContext = reactContext;
  }

  @Override
  public String getName() {
    return "RNZendeskChat";
  }

  private void setupChatObserver(){
        isVisitorInfoSet = false;
        final ObservationScope observationScope = new ObservationScope();
        final ProfileProvider profileProvider =  Chat.INSTANCE.providers().profileProvider();

        Chat.INSTANCE.providers().chatProvider().observeChatState(observationScope, new Observer<ChatState>() {
            @Override
            public void update(ChatState chatState) {
                ChatSessionStatus chatStatus = chatState.getChatSessionStatus();
                // Status achieved after the PreChatForm is completed
                if (chatStatus == ChatSessionStatus.STARTED) {
                    // Update the information MID chat here. All info but Department can be updated
                    if (!isVisitorInfoSet && builtVisitorInfo != null) {
                        profileProvider.setVisitorInfo(builtVisitorInfo, null);
                        isVisitorInfoSet = true;
                        Log.d(TAG, "[observerSetup] - Updated VisitorInfo!");
                    }
                }
            }
        });
    }

  /* helper methods */
  private Boolean getBoolean(ReadableMap options, String key){
    if(options.hasKey(key)){
      return options.getBoolean(key);
    }
    return null;
  }

  private String getString(ReadableMap options, String key){
    if(options.hasKey(key)){
      return options.getString(key);
    }
    return null;
  }

  @ReactMethod
    public void setVisitorInfo(ReadableMap visitorInfo) {
        Providers providers = Chat.INSTANCE.providers();
        if (providers == null) {
            Log.d(TAG, "Can't set visitor info, Chat Instance Providers is null");
            return;
        }

        ChatProvider chatProvider = providers.chatProvider();
        if (chatProvider != null) {
            if (visitorInfo.hasKey("department") && visitorInfo.getString("department") != null) {
                String department = visitorInfo.getString("department");
                chatProvider.setDepartment(department, null);
            }
        } else {
            Log.d(TAG, "Can't set department because Chat provider is null");
        }

        VisitorInfo.Builder visitorInfoBuilder = VisitorInfo.builder();

        if (visitorInfo.hasKey("name")) {
            String name = visitorInfo.getString("name");
            visitorInfoBuilder.withName(name);
        }
        if (visitorInfo.hasKey("email")) {
            String email = visitorInfo.getString("email");
            visitorInfoBuilder.withEmail(email);
        }
        if (visitorInfo.hasKey("phone")) {
            String phone = visitorInfo.getString("phone");
            visitorInfoBuilder.withPhoneNumber(phone);
        }

        builtVisitorInfo = visitorInfoBuilder.build();

        ProfileProvider profileProvider = providers.profileProvider();
        if (profileProvider == null) {
            Log.d(TAG, "Can't set visitor info, because Profile provider is null");
            return;
        }

        if(visitorInfo.hasKey("tags")) {
            ReadableArray readableTags = visitorInfo.getArray("tags");
            List<String> tags = new ArrayList<String>();

            for (int i = 0; i < readableTags.size(); i++) {
                tags.add(readableTags.getString(i));
            }

            profileProvider.addVisitorTags(tags, null);
        }

        Log.d(TAG, "Visitor Info set with success: " + visitorInfo);
    }

    @ReactMethod
    public void init(ReadableMap options) {
        String appId = options.getString("appId");
        String clientId = options.getString("clientId");
        String url = options.getString("url");
        String key = options.getString("key");
        Context context = appContext;
        Zendesk.INSTANCE.init(context, url, appId, clientId);
        Support.INSTANCE.init(Zendesk.INSTANCE);
        AnswerBot.INSTANCE.init(Zendesk.INSTANCE, Support.INSTANCE);
        Chat.INSTANCE.init(context, key);
    }

    @ReactMethod
    public void initChat(String key) {
        Context context = appContext;
        Chat.INSTANCE.init(context, key);
    }

    @ReactMethod
    public void resetUserIdentity() {
        Chat.INSTANCE.resetIdentity(new CompletionCallback<Void>()  {
            @Override
            public void onCompleted(Void result) {
                // Identity was reset
                Log.d(TAG, "User identity was reset with success.");
            }
        });
    }

    @ReactMethod
    public void setUserIdentity(ReadableMap userIdentityInfo) {
        if (userIdentityInfo.hasKey("token")) {
            String token = userIdentityInfo.getString("token");
            Identity identity = new JwtIdentity(token);

            Zendesk.INSTANCE.setIdentity(identity);
            Log.d(TAG, "User Identity set with token: " + token);
        } else {
            String name = userIdentityInfo.getString("name");
            String email = userIdentityInfo.getString("email");
            Identity identity = new AnonymousIdentity.Builder()
                    .withNameIdentifier(name)
                    .withEmailIdentifier(email)
                    .build();

            Zendesk.INSTANCE.setIdentity(identity);
            Log.d(TAG, "User Identity set with name: " + name + " and email: " + email);
        }
    }

    @ReactMethod
    public void showHelpCenter(ReadableMap options) {
        String botName = options.hasKey("botName") ? options.getString("botName") : "Chat Bot";
        Activity activity = getCurrentActivity();
        if (options.hasKey("withChat")) {
            HelpCenterActivity.builder()
             .withEngines(ChatEngine.engine())
             .show(activity);
        } else if (options.hasKey("disableTicketCreation")) {
            HelpCenterActivity.builder()
              .withContactUsButtonVisible(false)
              .withShowConversationsMenuButton(false)
              .show(activity, ViewArticleActivity.builder()
                                                 .withContactUsButtonVisible(false)
                                                 .config());
        } else {
            HelpCenterActivity.builder()
             .show(activity);
        }
    }

    

    private PreChatFormFieldStatus getPreChatOptionsValue(ReadableMap options, String key) {
        if (!options.hasKey(key)) return PreChatFormFieldStatus.OPTIONAL;
        switch (options.getString(key)) {
            case "required": return PreChatFormFieldStatus.REQUIRED;
            case "optional": return PreChatFormFieldStatus.OPTIONAL;
            case "hidden": return PreChatFormFieldStatus.HIDDEN;
            default: return PreChatFormFieldStatus.OPTIONAL;
        }
    }

    private Boolean getChatOptionsValue(ReadableMap options, String key) {
        if (!options.hasKey(key)) return true;
        return options.getBoolean(key);
    }

    @ReactMethod
    public void startChat(ReadableMap options) {
        if(options.hasKey("userIdentity")) {
            setUserIdentity(options.getMap("userIdentity"));
        }

        if(options.hasKey("visitorInfo")) {
            setVisitorInfo(options.getMap("visitorInfo"));
        }

        Activity activity = getCurrentActivity();
        MessagingConfiguration.Builder messagingActivityBuilder = MessagingActivity.builder();

        if(options.hasKey("toolbarTitle")) {
            String toolbarTitle = options.getString("toolbarTitle");
            messagingActivityBuilder.withToolbarTitle(toolbarTitle);
        }

        String botName = "Answer Bot";

        if(options.hasKey("botName")) {
            botName = options.getString("botName");
        }

        messagingActivityBuilder.withBotLabelString(botName);

        if (options.hasKey("chatOnly")) {
            messagingActivityBuilder.withEngines(ChatEngine.engine());
        } else {
            messagingActivityBuilder.withEngines(AnswerBotEngine.engine(), ChatEngine.engine(), SupportEngine.engine());
        }

        ReadableMap chatConfigOptions = null;

        if(options.hasKey("chatConfigurationOptions")) {
            chatConfigOptions = options.getMap("chatConfigurationOptions");
        }

        setupChatObserver();

        messagingActivityBuilder.show(activity, getChatConfiguration(chatConfigOptions));
        Log.d(TAG, "Started Chat with success!");
    }

    private ChatConfiguration getChatConfiguration(ReadableMap chatConfigurationOptions) {

        ChatConfiguration.Builder chatConfigurationBuilder = ChatConfiguration.builder();

        if(chatConfigurationOptions != null) {
            if(chatConfigurationOptions.hasKey("enableChatMenuActions")) {
                boolean isMenuActionsEnabled = chatConfigurationOptions.getBoolean("enableChatMenuActions");

                if(isMenuActionsEnabled) {
                    if(chatConfigurationOptions.hasKey("chatMenuActions")) {
                        ReadableMap chatMenuActions = chatConfigurationOptions.getMap("chatMenuActions");
                        boolean isEndChatMenuItemEnabled = true;
                        boolean isChatTranscriptMenuItemEnabled = true;

                        if(chatMenuActions.hasKey("enableEndChatMenuItem")) {
                            isEndChatMenuItemEnabled = chatMenuActions.getBoolean("enableEndChatMenuItem");
                        }
                        if(chatMenuActions.hasKey("enableChatTranscriptMenuItem")) {
                            isChatTranscriptMenuItemEnabled = chatMenuActions.getBoolean("enableChatTranscriptMenuItem");
                        }

                        boolean enableOnlyEndChat = isEndChatMenuItemEnabled == true && isChatTranscriptMenuItemEnabled ==  false;
                        boolean enableOnlyChatTranscript = isEndChatMenuItemEnabled == false && isChatTranscriptMenuItemEnabled ==  true;

                        if(enableOnlyEndChat) {
                            chatConfigurationBuilder.withChatMenuActions(ChatMenuAction.END_CHAT);
                        } else if(enableOnlyChatTranscript) {
                            chatConfigurationBuilder.withChatMenuActions(ChatMenuAction.CHAT_TRANSCRIPT);
                        }
                    }
                } else {
                    chatConfigurationBuilder.withChatMenuActions();
                }
            }

            if(chatConfigurationOptions.hasKey("enableAgentAvailability")) {
                boolean isAgentAvailabilityEnabled = chatConfigurationOptions.getBoolean("enableAgentAvailability");
                chatConfigurationBuilder.withAgentAvailabilityEnabled(isAgentAvailabilityEnabled);
            }

            if(chatConfigurationOptions.hasKey("enableChatTranscriptPrompt")) {
                boolean isChatTranscriptPromptEnabled = chatConfigurationOptions.getBoolean("enableChatTranscriptPrompt");
                chatConfigurationBuilder.withTranscriptEnabled(isChatTranscriptPromptEnabled);
            }

            if(chatConfigurationOptions.hasKey("enableOfflineForm")) {
                boolean isOfflineFormEnabled = chatConfigurationOptions.getBoolean("enableOfflineForm");
                chatConfigurationBuilder.withOfflineFormEnabled(isOfflineFormEnabled);
            }

            if(chatConfigurationOptions.hasKey("enablePreChatForm")) {
                boolean isPreChatFormEnabled = chatConfigurationOptions.getBoolean("enablePreChatForm");
                chatConfigurationBuilder.withPreChatFormEnabled(isPreChatFormEnabled);

                if(isPreChatFormEnabled == true && chatConfigurationOptions.hasKey("preChatFormOptions")) {
                    ReadableMap preChatFormOptions = chatConfigurationOptions.getMap("preChatFormOptions");

                    if(preChatFormOptions.hasKey("name")) {
                        chatConfigurationBuilder.withNameFieldStatus(PreChatFormFieldStatus.valueOf(preChatFormOptions.getString("name")));
                    }
                    if(preChatFormOptions.hasKey("email")) {
                        chatConfigurationBuilder.withEmailFieldStatus(PreChatFormFieldStatus.valueOf(preChatFormOptions.getString("email")));
                    }
                    if(preChatFormOptions.hasKey("phone")) {
                        chatConfigurationBuilder.withPhoneFieldStatus(PreChatFormFieldStatus.valueOf(preChatFormOptions.getString("phone")));
                    }
                    if(preChatFormOptions.hasKey("department")) {
                        chatConfigurationBuilder.withDepartmentFieldStatus(PreChatFormFieldStatus.valueOf(preChatFormOptions.getString("department")));
                    }
                }
            }
        }

        return chatConfigurationBuilder.build();
    }

    @ReactMethod
    public void setNotificationToken(String token) {
        PushNotificationsProvider pushProvider = Chat.INSTANCE.providers().pushNotificationsProvider();
        if (pushProvider != null) {
            pushProvider.registerPushToken(token);
        }
    }
}