package com.linx.lio;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaPlugin;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;

import cielo.orders.domain.Credentials;

public class Lio extends CordovaPlugin {

    private static final String INIT = "init";
    private static final String BIND = "bind";
    private static final String UNBIND = "unbind";
    private static final String IS_BOUND = "isBound";
    private static final String PLACE_ORDER = "placeOrder";
    private static final String CHECKOUT = "checkout";
    private static final String CONFIRM_ORDER = "confirmOrder";
    private static final String CANCEL_ORDER = "cancelOrder";

    private LioPaymentManager lioPaymentManager;

    public boolean execute(final String action, final CordovaArgs args, final CallbackContext callbackContext)
            throws JSONException {
        final JSONObject req = args.getJSONObject(0);

        if (INIT.equals(action)) {
            init(InitRequest.fromJSONObject(req), callbackContext);
            return true;
        } else if (BIND.equals(action)) {
            bind(callbackContext);
            return true;
        } else if (UNBIND.equals(action)) {
            unbind(callbackContext);
            return true;
        } else if (IS_BOUND.equals(action)) {
            isBound(callbackContext);
            return true;
        } else if (PLACE_ORDER.equals(action)) {
            placeOrder(PlaceOrderRequest.fromJSONObject(req), callbackContext);
            return true;
        } else if (CHECKOUT.equals(action)) {
            checkout(CheckoutRequest.fromJSONObject(req), callbackContext);
            return true;
        } else if (CONFIRM_ORDER.equals(action)) {
            confirmOrder(ConfirmOrderRequest.fromJSONObject(req), callbackContext);
            return true;
        } else if (CANCEL_ORDER.equals(action)) {
            cancelOrder(CancelOrderRequest.fromJSONObject(req), callbackContext);
            return true;
        }

        return false;
    }

    private void init(@NotNull final InitRequest initRequest,
                      @NotNull final CallbackContext callbackContext) {
        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                if (lioPaymentManager != null && lioPaymentManager.isBound()) {
                    throw new RuntimeException("unbind before re-initializing");
                }
                final Credentials credentials = new Credentials(initRequest.getClientId(),
                        initRequest.getToken());
                lioPaymentManager = new LioPaymentManager(credentials, cordova.getActivity());
                callbackContext.success("SUCCESS");
            }
        });
    }

    private void bind(@NotNull final CallbackContext callbackContext) {
        requiresInit();

        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                lioPaymentManager.bind(callbackContext);
            }
        });
    }

    private void unbind(@NotNull final CallbackContext callbackContext) {
        requiresInit();

        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                lioPaymentManager.unbind();
                callbackContext.success("SUCCESS");
            }
        });
    }

    private void isBound(@NotNull final CallbackContext callbackContext) {
        requiresInit();

        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                if (lioPaymentManager.isBound()) {
                    callbackContext.success("BOUND");
                } else {
                    callbackContext.error("NOT_BOUND");
                }
            }
        });
    }

    private void placeOrder(@NotNull final PlaceOrderRequest placeOrderRequest,
                            @NotNull final CallbackContext callbackContext) {
        requiresInit();

        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                lioPaymentManager.placeOrder(placeOrderRequest, callbackContext);
            }
        });
    }

    private void checkout(@NotNull final CheckoutRequest checkoutRequest,
                          @NotNull final CallbackContext callbackContext) {
        requiresInit();

        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                lioPaymentManager.checkout(checkoutRequest, callbackContext);
            }
        });
    }

    private void confirmOrder(@NotNull final ConfirmOrderRequest confirmOrderRequest,
                              @NotNull final CallbackContext callbackContext) {
        requiresInit();

        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                lioPaymentManager.confirmOrder(confirmOrderRequest, callbackContext);
            }
        });
    }

    private void cancelOrder(@NotNull final CancelOrderRequest cancelOrderRequest,
                             @NotNull final CallbackContext callbackContext) {
        requiresInit();

        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                lioPaymentManager.cancelOrder(cancelOrderRequest, callbackContext);
            }
        });
    }

    private void requiresInit() {
        if (lioPaymentManager == null) {
            throw new IllegalStateException("call init before calling other functions");
        }
    }
}
