package com.mobify.astro;

import android.support.annotation.NonNull;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.WebView;

import com.mobify.astro.messaging.EventMessage;
import com.mobify.astro.messaging.EventRegistrar;
import com.mobify.astro.messaging.MessageSender;
import com.mobify.astro.messaging.annotations.RpcMethod;
import com.mobify.astro.plugins.AstroNative;
import com.mobify.astro.plugins.webviewplugin.AstroWebViewPlugin;
import com.mobify.astro.utilities.AstroWebUtilities;

import org.apache.cordova.CordovaWebView;

public class AstroWorker extends AstroWebViewPlugin {
    private static final String TAG = AstroWorker.class.getName();

    public static final String ADDRESS = "AstroWorker:0";

    CordovaLoader cordovaLoader = new CordovaLoader();

    WebView webView;
    CordovaWebView cordovaWebView;

    public AstroWorker(@NonNull AstroActivity activity, @NonNull PluginManager pluginManager,
                       @NonNull EventRegistrar eventRegistrar, @NonNull MessageSender messageSender) {
        super(activity, pluginManager, eventRegistrar, messageSender);

        activity.client = cordovaLoader;

        loadCordova();

        webView.addJavascriptInterface(this, "Astro");

        // Inject AstroNativeObject in constructor to ensure that it is always accessible
        webView.addJavascriptInterface(new AstroNative(), "AstroNativeObject");

        AstroWebUtilities.addAstroUserAgent(activity, webView.getSettings());

        // Wait for Cordova to be loaded before we do any more "loading"
    }

    /**
     * Fetch the address for the AstroWorker
     *
     * @return String representation of the AstroWorker address
     */
    @Override
    public String getInstanceAddress() {
        return ADDRESS;
    }

    @Override
    public View getView() {
        return webView;
    }

    @Override
    public WebView getWebView() {
        return webView;
    }

    /**
     * Loads the app.js that ships with the SDK.
     */
    public void loadDefault() {
        load("../app.js");
    }

    /**
     * Loads given `app` file as app.js.
     */
    public void load(String app) {
        Log.d(TAG, "Loading Astro...");
        String appJS = "javascript:(function(d) {" +
                "  console.log('Loading Astro...');" +
                "  var s = d.createElement('script');" +
                "  s.src = '" + app + "';" +
                "  s.type = 'text/javascript';" +
                "  console.log(d.documentElement.outerHTML);" +
                "  d.getElementsByTagName('head')[0].appendChild(s);" +
                "})(document);";

        cordovaWebView.loadUrl(appJS);

        // Indicate that the web view is loaded and ready to receive messages.
        // TODO: Consider moving this to onPageFinished inside of a WebViewClient instead. It's
        //       unclear whether flushing the JavaScript queue works at this point, but the queue
        //       should always currently be empty at this point anyway.
        setJsLoaded(true);
    }

    /**
     * Subscribes app.js to events that happen on the plugin with the given address
     * @param address The address of the plugin who's events app.js should listen for
     */
    @RpcMethod(methodName = "subscribeToEvents", parameterNames = {"address"})
    public void subscribeToEvents(String address) {
        listenForMessagesOnAddress(address + ":" + EventMessage.EVENTS_KEYWORD);
    }

    /**
     * Forwards `console.log` messages to Xcode console, defined here for completeness
     */
    @RpcMethod(methodName = "logMessage", parameterNames = {"message"})
    public void logMessage(String message) {
        //No op for Android
    }

    private void loadCordova() {
        activity.startCordova();

        cordovaWebView = activity.getCordovaWebView();

        // Cordova routes back button presses to the Cordova web view by default, let's undo that
        cordovaWebView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, false);

        webView = (WebView)(cordovaWebView.getView());
    }

    class CordovaLoader implements AstroActivity.AstroActivityClient {
        @Override
        public void cordovaLoaded() {
            webView.addJavascriptInterface(new AstroNative(), "AstroNativeObject");
            loadDefault();
        }
    }
}
