package com.facebook.react.uimanager;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.RelativeLayout;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.uimanager.RootView;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.UIViewOperationQueue;
import com.facebook.react.views.textinput.ReactEditText;

public class RNCustomKeyboardKitModule extends ReactContextBaseJavaModule {

  private final ReactApplicationContext reactContext;

  private final int TAG_ID = 0xdeadbeaf;

  public RNCustomKeyboardKitModule(ReactApplicationContext reactContext) {
    super(reactContext);
    this.reactContext = reactContext;
  }

  Handler handle = new Handler(Looper.getMainLooper());

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

  private ReactEditText getEditById(int id) {
    // UIViewOperationQueue uii = this.getReactApplicationContext().getNativeModule(UIManagerModule.class).getUIImplementation().getUIViewOperationQueue();
    // return (ReactEditText) uii.getNativeViewHierarchyManager().resolveView(id);

    UIViewOperationQueue uii = null;
    ReactEditText edit = null;

    while (edit == null) {
      uii = this.getReactApplicationContext().getNativeModule(UIManagerModule.class).getUIImplementation().getUIViewOperationQueue();

      try {
        edit = (ReactEditText) uii.getNativeViewHierarchyManager().resolveView(id);
      } catch (IllegalViewOperationException e) {

      }
    }

    return edit;
  }

  @ReactMethod
  public void install(final int tag, final String type) {
    UiThreadUtil.runOnUiThread(new Runnable() {
        @Override
        public void run() {
          final Activity activity = getCurrentActivity();
          final ReactEditText edit = getEditById(tag);

          if (edit == null) {
            return;
          }

          edit.setTag(TAG_ID, createCustomKeyboardKit(activity, tag, type));

          edit.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(final View v, boolean hasFocus) {
              if (hasFocus) {
                View keyboard = (View)edit.getTag(TAG_ID);
                if (keyboard.getParent() == null) {
                   activity.addContentView(keyboard, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
                }
                UiThreadUtil.runOnUiThread(new Runnable() {
                  @Override
                  public void run() {
                    ((InputMethodManager) getReactApplicationContext().getSystemService(Activity.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
                  }
                });
              } else {
                View keyboard = (View)edit.getTag(TAG_ID);
                if (keyboard.getParent() != null) {
                  ((ViewGroup) keyboard.getParent()).removeView(keyboard);
                }
              }
            }
          });

          edit.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(final View v) {
              View keyboard = (View)edit.getTag(TAG_ID);
              if (keyboard.getParent() == null) {
                activity.addContentView(keyboard, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
              }
              UiThreadUtil.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                  ((InputMethodManager) getReactApplicationContext().getSystemService(Activity.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
              });
            }
          });
        }
    });
  }

  ReactRootView rootView = null;

  private View createCustomKeyboardKit(Activity activity, int tag, String type) {
    RelativeLayout layout = new RelativeLayout(activity);
    rootView = new ReactRootView(this.getReactApplicationContext());
    rootView.setBackgroundColor(Color.WHITE);

    Bundle bundle = new Bundle();
    bundle.putInt("tag", tag);
    bundle.putString("type", type);
    rootView.startReactApplication(
            ((ReactApplication) activity.getApplication()).getReactNativeHost().getReactInstanceManager(),
            "CustomKeyboardKit",
            bundle);

    final float scale = activity.getResources().getDisplayMetrics().density;
    RelativeLayout.LayoutParams lParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, Math.round(216*scale));
    lParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
    layout.addView(rootView, lParams);
    // activity.addContentView(layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    return layout;
  }

  @ReactMethod
  public void uninstall(final int tag) {
    UiThreadUtil.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        final Activity activity = getCurrentActivity();
        final ReactEditText edit = getEditById(tag);
        if (edit == null) {
          return;
        }

        edit.setTag(TAG_ID, null);
      }
    });
  }

  @ReactMethod
  public void insertText(final int tag, final String text) {
    UiThreadUtil.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        final Activity activity = getCurrentActivity();
        final ReactEditText edit = getEditById(tag);
        if (edit == null) {
          return;
        }

        int start = Math.max(edit.getSelectionStart(), 0);
        int end = Math.max(edit.getSelectionEnd(), 0);
        edit.getText().replace(Math.min(start, end), Math.max(start, end),
                text, 0, text.length());
      }
    });
  }

  @ReactMethod
  public void backSpace(final int tag) {
    UiThreadUtil.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        final Activity activity = getCurrentActivity();
        final ReactEditText edit = getEditById(tag);
        if (edit == null) {
          return;
        }

        int start = Math.max(edit.getSelectionStart(), 0);
        int end = Math.max(edit.getSelectionEnd(), 0);
        if (start != end) {
          edit.getText().delete(start, end);
        } else if (start > 0){
          edit.getText().delete(start - 1, end);
        }
      }
    });
  }

  @ReactMethod
  public void doDelete(final int tag) {
    UiThreadUtil.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        final Activity activity = getCurrentActivity();
        final ReactEditText edit = getEditById(tag);
        if (edit == null) {
          return;
        }

        int start = Math.max(edit.getSelectionStart(), 0);
        int end = Math.max(edit.getSelectionEnd(), 0);
        if (start != end) {
          edit.getText().delete(start, end);
        } else if (start > 0){
          edit.getText().delete(start, end+1);
        }
      }
    });
  }

  @ReactMethod
  public void moveLeft(final int tag) {
    UiThreadUtil.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        final Activity activity = getCurrentActivity();
        final ReactEditText edit = getEditById(tag);
        if (edit == null) {
          return;
        }

        int start = Math.max(edit.getSelectionStart(), 0);
        int end = Math.max(edit.getSelectionEnd(), 0);
        if (start != end) {
          edit.setSelection(start, start);
        } else {
          edit.setSelection(start - 1, start - 1);
        }
      }
    });
  }

  @ReactMethod
  public void moveRight(final int tag) {
    UiThreadUtil.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        final Activity activity = getCurrentActivity();
        final ReactEditText edit = getEditById(tag);
        if (edit == null) {
          return;
        }

        int start = Math.max(edit.getSelectionStart(), 0);
        int end = Math.max(edit.getSelectionEnd(), 0);
        if (start != end) {
          edit.setSelection(end, end);
        } else if (start > 0){
          edit.setSelection(end + 1, end + 1);
        }
      }
    });
  }

  @ReactMethod
  public void switchSystemKeyboard(final int tag) {
    UiThreadUtil.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        final Activity activity = getCurrentActivity();
        final ReactEditText edit = getEditById(tag);
        if (edit == null) {
          return;
        }

        View keyboard = (View)edit.getTag(TAG_ID);
        if (keyboard.getParent() != null) {
          ((ViewGroup) keyboard.getParent()).removeView(keyboard);
        }
        UiThreadUtil.runOnUiThread(new Runnable() {
          @Override
          public void run() {
            ((InputMethodManager) getReactApplicationContext().getSystemService(Activity.INPUT_METHOD_SERVICE)).showSoftInput(edit, InputMethodManager.SHOW_IMPLICIT);
          }
        });
      }
    });
  }

  @ReactMethod
  public void hideKeyboard(final int tag) {
    UiThreadUtil.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        final ReactEditText edit = getEditById(tag);
        if (edit == null) {
          return;
        }
        
        View keyboard = (View)edit.getTag(TAG_ID);
        if (keyboard.getParent() != null) {
          ((ViewGroup) keyboard.getParent()).removeView(keyboard);
        }
      }
    });
  }
}