package com.contentsquare.rn.webview;

import android.app.Activity;
import android.graphics.Bitmap;
import android.util.Log;
import android.webkit.WebBackForwardList;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import androidx.annotation.NonNull;

import com.contentsquare.android.R;
import com.contentsquare.android.api.CsWebViewManager;
import com.contentsquare.rn.utils.ReactNativeViewFinder;
import com.contentsquare.rn.utils.VersionUtils;
import com.contentsquare.rn.utils.WebViewUtils;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.modules.core.DeviceEventManagerModule;

/**
 * Handle injection and removal of the JS interface in React Native WebViews.
 */
public class WebViewInjector {

    @NonNull
    private final ReactNativeViewFinder mReactNativeViewFinder;

    @NonNull
    private final WebViewInjector.SDKWebViewManager mSDKWebViewManager;

    public static class SDKWebViewManager {
        public void injectWebView(@NonNull final WebView webView) {
            CsWebViewManager.INSTANCE.injectEventTrackingInterface(webView);
        }

        public void removeWebViewInjection(@NonNull final WebView webView) {
            CsWebViewManager.INSTANCE.removeEventTrackingInterface(webView);
        }
    }

    /**
     * Constructor.
     *
     * @param reactNativeViewFinder as {@link ReactNativeViewFinder}
     * @param webViewManager        as {@link SDKWebViewManager}
     */
    public WebViewInjector(@NonNull ReactNativeViewFinder reactNativeViewFinder,
            @NonNull SDKWebViewManager webViewManager) {
        this.mReactNativeViewFinder = reactNativeViewFinder;
        this.mSDKWebViewManager = webViewManager;
    }

    /**
     * inject a javascript interface to a React Native webView.
     *
     * @param reactContext React Native context.
     * @param webViewTag   the webView's react tag.
     */
    public void injectWebView(@NonNull final ReactApplicationContext reactContext, final int webViewTag) {
        final Activity activity = reactContext.getCurrentActivity();
        if (activity == null) {
            return;
        }

        mReactNativeViewFinder.findWebView(reactContext, webViewTag, webView -> {
            Log.i("CSLIB", "WebView found in native bridge. Ready to be injected");

            mSDKWebViewManager.injectWebView(prepareWebView(activity, webView));
            
            // getting React Native's webview client before Android Native SDK sets its own
            WebViewClient rnWebViewClient = WebViewUtils.INSTANCE.getWebViewClient(webView);

            // replacing Native SDK webview client with custom one
            handleBlankPageRemoval(webView, rnWebViewClient);
            reactContext
                    .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                    .emit("onCSWebViewInjected", null);
        });
    }

    /*
    * removes "about:blank" from history. This page is added due to the current implementation in RN
    *
    * this method only works for API levels 26 and up
    * */
    private void handleBlankPageRemoval(WebView webView, WebViewClient rnWebViewClient) {
        if (VersionUtils.INSTANCE.isApiLevelAtLeast(android.os.Build.VERSION_CODES.O)) {
            if (rnWebViewClient != null) {
                webView.setWebViewClient(new BridgeWebViewClient(rnWebViewClient) {
                    @Override
                    public void onPageStarted(WebView view, String url, Bitmap favicon) {
                        super.onPageStarted(view, url, favicon);
                        WebBackForwardList backForwardList = webView.copyBackForwardList();

                        // We need to remove the blank page introduced when loading the first time with "undefined" url from JS
                        if (backForwardList.getSize() == 2 && "about:blank".equals(backForwardList.getItemAtIndex(0).getOriginalUrl())) {
                            webView.clearHistory();
                        }

                    }
                });
            } else {
                Log.i("CSLIB", "Handling blank page removal not performed: web client not found");
            }
        } else {
            Log.i("CSLIB", "Handling blank page removal not performed: API leve lower than 26");
        }
    }

    /**
     * remove a javascript interface from a React Native webView.
     *
     * @param reactContext React Native context.
     * @param webViewTag   the webView's react tag.
     */
    public void removeWebViewInjection(@NonNull final ReactApplicationContext reactContext, final int webViewTag) {
        final Activity activity = reactContext.getCurrentActivity();

        if (activity == null) {
            return;
        }

        mReactNativeViewFinder.findWebView(reactContext, webViewTag, webView -> {
            Log.i("CSLIB", "WebView found in native bridge. Ready to remove injection");
            mSDKWebViewManager.removeWebViewInjection(prepareWebView(activity, webView));
        });
    }

    @NonNull
    private WebView prepareWebView(@NonNull final Activity activity, @NonNull final WebView webView) {
        webView.setTag(R.string.contentsquare_react_native_web_view_activity_tag, activity);
        return webView;
    }
}