package com.wix.reactnativeuilib.keyboardinput;

import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.lang.ref.WeakReference;

import static com.wix.reactnativeuilib.keyboardinput.AppContextHolder.getCurrentActivity;
import static com.wix.reactnativeuilib.keyboardinput.utils.RuntimeUtils.dispatchUIUpdates;
import static com.wix.reactnativeuilib.keyboardinput.utils.RuntimeUtils.runOnUIThread;
import static com.wix.reactnativeuilib.keyboardinput.utils.ViewUtils.getWindow;

public class CustomKeyboardLayout implements ReactSoftKeyboardMonitor.Listener, ReactScreenMonitor.Listener {
    private boolean mFirstKeyboardShow = true;
    private final InputMethodManager mInputMethodManager;
    private final ReactSoftKeyboardMonitor mKeyboardMonitor;
    private WeakReference<CustomKeyboardRootViewShadow> mShadowNode = new WeakReference<>(null);
    private int mSoftInputMode;
    private boolean mIsShown = false;

    public CustomKeyboardLayout(ReactContext reactContext, ReactSoftKeyboardMonitor keyboardMonitor, ReactScreenMonitor screenMonitor) {
        mKeyboardMonitor = keyboardMonitor;
        mInputMethodManager = (InputMethodManager) reactContext.getSystemService(Context.INPUT_METHOD_SERVICE);

        mKeyboardMonitor.setListener(this);
        screenMonitor.addListener(this);
    }

    public void setShown(boolean isShown) {
        mIsShown = isShown;
        Window window = getWindow();
        if (window != null) {
            if (mIsShown) {
                mSoftInputMode = window.getAttributes().softInputMode;
            } else {
                window.setSoftInputMode(mSoftInputMode);
            }
        }
    }

    @Override
    public void onSoftKeyboardVisible(boolean distinct) {
        if (distinct) {
            clearKeyboardOverlayMode();
        }
        hideCustomKeyboardContent();
    }

    @Override
    public void onSoftKeyboardHidden() {
        if (getShadowNodeHeight() == 0) {
            mFirstKeyboardShow = true;
        }
    }

    @Override
    public void onNewReactScreen(ReactRootView reactRootView) {
        clearKeyboardOverlayMode();
        if (reactRootView != null) {
            sendCustomKeyboardResignedEvent();
        }
    }

    public void setShadowNode(CustomKeyboardRootViewShadow node) {
        mShadowNode = new WeakReference<>(node);
    }

    public void onKeyboardHasCustomContent() {
        runOnUIThread(new Runnable() {
            @Override
            public void run() {
                showCustomKeyboardContent();
                setKeyboardOverlayMode();
                hideSoftKeyboardIfNeeded();
            }
        });
    }

    public void forceReset(final Promise promise) {
        runOnUIThread(new Runnable() {
            @Override
            public void run() {
                Activity currentActivity = getCurrentActivity();
                if (currentActivity != null) {
                    final View focusedView = currentActivity.getCurrentFocus();
                    if (focusedView instanceof EditText) {
                        showSoftKeyboard();
                    } else {
                        hideCustomKeyboardContent();
                        clearKeyboardOverlayMode();
                    }
                    promise.resolve(null);
                }
            }
        });
    }

    public void clearFocusedView() {
        runOnUIThread(new Runnable() {
            @Override
            public void run() {
                Activity currentActivity = getCurrentActivity();
                if (currentActivity != null) {
                    final View focusedView = currentActivity.getCurrentFocus();
                    if (focusedView != null) {
                        focusedView.clearFocus();
                    }
                }
            }
        });
    }

    private void showCustomKeyboardContent() {
        setCustomKeyboardHeight(getHeightForCustomContent());
    }

    private void hideCustomKeyboardContent() {
        setCustomKeyboardHeight(0);
        runOnUIThread(new Runnable() {
            @Override
            public void run() {
                sendCustomKeyboardResignedEvent();
            }
        });
    }

    private void syncCustomKeyboardHeightAfterUIUpdate(final int height) {
        dispatchUIUpdates(new Runnable() {
            @Override
            public void run() {
                setShadowNodeHeight(height);
            }
        });
    }

    private void setCustomKeyboardHeight(int height) {
        try {
            if (mFirstKeyboardShow) {
                mFirstKeyboardShow = false;
                syncCustomKeyboardHeightAfterUIUpdate(height);
            } else {
                setShadowNodeHeight(height);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void setShadowNodeHeight(int height) {
        final CustomKeyboardRootViewShadow shadowNode = mShadowNode.get();
        if (shadowNode != null) {
            shadowNode.setHeight(height);
        }
    }

    private float getShadowNodeHeight() {
        float height = 0;
        final CustomKeyboardRootViewShadow shadowNode = mShadowNode.get();
        if (shadowNode != null) {
            height = shadowNode.getHeight();
        }
        return height;
    }

    private void showSoftKeyboard() {
        mInputMethodManager.showSoftInput(getCurrentActivity().getCurrentFocus(), 0);
    }

    private void hideSoftKeyboardIfNeeded() {
        final View focusedView = getCurrentActivity().getCurrentFocus();
        if (focusedView != null) {
            mInputMethodManager.hideSoftInputFromWindow(focusedView.getWindowToken(), 0);
        }
    }

    private int getHeightForCustomContent() {
        return mKeyboardMonitor.getKeyboardHeight();
    }

    private void setKeyboardOverlayMode() {
        setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
    }

    private void clearKeyboardOverlayMode() {
        setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    }

    private void setSoftInputMode(int softInputMode) {
        if (mIsShown) {
            Window window = getWindow();
            if (window != null) {
                window.setSoftInputMode(softInputMode);
            }
        }
    }

    private void sendCustomKeyboardResignedEvent() {
        if (ReactContextHolder.getContext().hasActiveCatalystInstance()) {
            ReactContextHolder.getContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("kbdResigned", null);
        }
    }

}
