package com.jordansexton.react.crosswalk.webview;

import android.app.Activity;
import android.content.Intent;

import com.facebook.react.bridge.BaseActivityEventListener;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
import org.xwalk.core.XWalkNavigationHistory;
import org.xwalk.core.XWalkView;

import org.json.JSONObject;
import org.json.JSONException;

import com.facebook.react.views.webview.events.TopMessageEvent;

import javax.annotation.Nullable;
import java.util.Map;

public class CrosswalkWebViewGroupManager extends ViewGroupManager<CrosswalkWebView> {

    public static final int GO_BACK = 1;

    public static final int GO_FORWARD = 2;

    public static final int RELOAD = 3;

    public static final int POST_MESSAGE = 4;

    @VisibleForTesting
    public static final String REACT_CLASS = "CrosswalkWebView";

    private ReactApplicationContext reactContext;

    private static final String BLANK_URL = "about:blank";

    public CrosswalkWebViewGroupManager (ReactApplicationContext _reactContext) {
        reactContext = _reactContext;
    }

    @Override
    public String getName () {
        return REACT_CLASS;
    }

    @Override
    public CrosswalkWebView createViewInstance (ThemedReactContext context) {
        Activity _activity = reactContext.getCurrentActivity();
        CrosswalkWebView crosswalkWebView = new CrosswalkWebView(context, _activity);
        context.addLifecycleEventListener(crosswalkWebView);
        reactContext.addActivityEventListener(new XWalkActivityEventListener(crosswalkWebView));
        return crosswalkWebView;
    }

    @Override
    public void onDropViewInstance(CrosswalkWebView view) {
        super.onDropViewInstance(view);
        ((ThemedReactContext) view.getContext()).removeLifecycleEventListener((CrosswalkWebView) view);
        view.onDestroy();
    }

    @ReactProp(name = "source")
    public void setSource(final CrosswalkWebView view, @Nullable ReadableMap source) {
      Activity _activity = reactContext.getCurrentActivity();
      if (_activity != null) {
          if (source != null) {
              if (source.hasKey("html")) {
                  final String html = source.getString("html");
                  _activity.runOnUiThread(new Runnable() {
                      @Override
                      public void run () {
                          view.load(null, html);
                      }
                  });
                  return;
              }
              if (source.hasKey("uri")) {
                  final String url = source.getString("uri");
                  _activity.runOnUiThread(new Runnable() {
                      @Override
                      public void run () {
                          view.load(url, null);
                      }
                  });
                  return;
              }
          }
      }
      setUrl(view, BLANK_URL);
    }


    @ReactProp(name = "injectedJavaScript")
    public void setInjectedJavaScript (XWalkView view, @Nullable String injectedJavaScript) {
        ((CrosswalkWebView) view).setInjectedJavaScript(injectedJavaScript);
    }

    @ReactProp(name = "messagingEnabled")
    public void setMessagingEnabled(XWalkView view, boolean enabled) {
        ((CrosswalkWebView) view).setMessagingEnabled(enabled);
    }

    @ReactProp(name = "url")
    public void setUrl (final CrosswalkWebView view, @Nullable final String url) {
        Activity _activity = reactContext.getCurrentActivity();
        if (_activity != null) {
            _activity.runOnUiThread(new Runnable() {
                @Override
                public void run () {
                    view.load(url, null);
                }
            });
        }
    }

    @ReactProp(name = "localhost")
    public void setLocalhost (CrosswalkWebView view, Boolean localhost) {
        view.setLocalhost(localhost);
    }

    @Override
    public
    @Nullable
    Map<String, Integer> getCommandsMap () {
        return MapBuilder.of(
            "goBack", GO_BACK,
            "goForward", GO_FORWARD,
            "reload", RELOAD,
            "postMessage", POST_MESSAGE
        );
    }

    @Override
    public void receiveCommand (CrosswalkWebView view, int commandId, @Nullable ReadableArray args) {
        switch (commandId) {
            case GO_BACK:
                view.getNavigationHistory().navigate(XWalkNavigationHistory.Direction.BACKWARD, 1);
                break;
            case GO_FORWARD:
                view.getNavigationHistory().navigate(XWalkNavigationHistory.Direction.FORWARD, 1);
                break;
            case RELOAD:
                view.reload(XWalkView.RELOAD_NORMAL);
                break;
            case POST_MESSAGE:
                try {
                    JSONObject eventInitDict = new JSONObject();
                    eventInitDict.put("data", args.getString(0));
                    view.evaluateJavascript("document.dispatchEvent(new MessageEvent('message', " + eventInitDict.toString() + "))", null);
                } catch (JSONException e) {
                    throw new RuntimeException(e);
                }
                break;
        }
    }

    @Override
    public Map getExportedCustomDirectEventTypeConstants () {
        return MapBuilder.of(
            NavigationStateChangeEvent.EVENT_NAME,
            MapBuilder.of("registrationName", "onCrosswalkWebViewNavigationStateChange"),
            ErrorEvent.EVENT_NAME,
            MapBuilder.of("registrationName", "onCrosswalkWebViewError"),
            ProgressEvent.EVENT_NAME,
            MapBuilder.of("registrationName", "onCrosswalkWebViewProgress"),
            TopMessageEvent.EVENT_NAME,
            MapBuilder.of("registrationName", "onMessage")
        );
    }

    protected class XWalkActivityEventListener extends BaseActivityEventListener {
        private CrosswalkWebView crosswalkWebView;

        public XWalkActivityEventListener(CrosswalkWebView _crosswalkWebView) {
            crosswalkWebView = _crosswalkWebView;
        }

        @Override
        public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
            crosswalkWebView.onActivityResult(requestCode, resultCode, data);
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            crosswalkWebView.onActivityResult(requestCode, resultCode, data);
        }
    }
}