package com.paygilant.cordovaWrapper;

import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;

import com.paygilant.PG_FraudDetection_SDK.Biometric.PaygilantScreenListener;
import com.paygilant.PG_FraudDetection_SDK.Communication.PaygilantCommunication;
import com.paygilant.PG_FraudDetection_SDK.PaygilantManager;
import com.paygilant.pgdata.CheckPoint.AddPaymentMethod;
import com.paygilant.pgdata.CheckPoint.CheckPoint;
import com.paygilant.pgdata.CheckPoint.CheckPointStatus;
import com.paygilant.pgdata.CheckPoint.CheckPointType;
import com.paygilant.pgdata.CheckPoint.General;
import com.paygilant.pgdata.CheckPoint.Launch;
import com.paygilant.pgdata.CheckPoint.Login;
import com.paygilant.pgdata.CheckPoint.Registration;
import com.paygilant.pgdata.CheckPoint.ScreenListenerType;
import com.paygilant.pgdata.CheckPoint.Transaction;
import com.paygilant.pgdata.CheckPoint.TransactionUpdate;

public class PaygilantBridge extends CordovaPlugin {

    private String requestId;

    PaygilantScreenListener paygilantScreenListener;

    @Override
    public boolean execute(final String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
        int argsCount = args.length();
        String[] strArgs = normalizeStringArgs(args);
        if (action.equals("init")) {
            if (argsCount < 1 || argsCount > 2 || strArgs[0] == null) {
                callbackContext.error("Expected one or two arguments.");
            } else {
                init(args.getString(0), argsCount == 2 ? args.getString(1) : null);
                callbackContext.success();
            }
        } else if (action.equals("setUserId")) {
            if (argsCount != 1) {
                callbackContext.error("Expected one arguments.");
            } else {
                PaygilantManager.getInstance(getApplicationContext()).setUserId(args.getString(0));
                callbackContext.success();
            }
        } else if (action.equals("getRiskForCheckPoint")) {
            CheckPoint checkPoint = jsonToCheckPoint(args.getJSONObject(0));
            requestId = PaygilantManager.getInstance(getApplicationContext()).getRiskForCheckPoint(checkPoint, new PaygilantCommunication() {
                @Override
                public void receiveRisk(int score, String s, String s1) {
                    if (score == -1) {
                        callbackContext.error("platform returned error");
                    } else {
                        try {
                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put("score", score);
                            jsonObject.put("requestId", requestId);
                            callbackContext.success(jsonObject);
                        } catch (JSONException e) {
                            callbackContext.error("json creation error");
                        }
                    }
                }
            });
        } else if (action.equals("arriveToCheckPoint")) {
            CheckPoint checkPoint = jsonToCheckPoint(args.getJSONObject(0));
            PaygilantManager.getInstance(getApplicationContext()).arriveToCheckPoint(checkPoint);
            callbackContext.success();
        } else if (action.equals("onRequestPermissionsResult")) {
            PaygilantManager.getInstance(getApplicationContext()).onRequestPermissionsResult(args.getInt(0), jsonArrayToStringArray(args.getJSONArray(1)), jsonArrayToIntArray(args.getJSONArray(2)));
            callbackContext.success();
        } else if (action.equals("updateCheckPointStatus")) {
            updateCheckPointStatus(args);
            callbackContext.success();
        } else if (action.equals("startScreenListener")) {
            paygilantScreenListener = PaygilantManager.getInstance(getApplicationContext()).startNewScreenListener(ScreenListenerType.valueOf(args.getString(0)), 0, getActivity());
            callbackContext.success();
        } else if (action.equals("startTouchListener")) {
            if (paygilantScreenListener != null) {
                paygilantScreenListener.StartTouchListener(getActivity());
                callbackContext.success();
            } else {
                callbackContext.error("startScreenListener not invoked before startTouchListener");
            }
        } else if (action.equals("pauseListenToSensors")) {
            if (paygilantScreenListener != null) {
                paygilantScreenListener.pauseListenToSensors();
                callbackContext.success();
            } else {
                callbackContext.error("startScreenListener not invoked before pauseListenToSensors");
            }
        } else if (action.equals("resumeListen")) {
            if (paygilantScreenListener != null) {
                paygilantScreenListener.resumeListen();
                callbackContext.success();
            } else {
                callbackContext.error("startScreenListener not invoked before resumeListen");
            }
        } else {
            return false;
        }
        return true;
    }

    private String[] normalizeStringArgs(JSONArray args) {
        String[] result = new String[args.length()];
        for (int i = 0; i < args.length(); i++) {
            String arg = null;
            try {
                arg = args.getString(i);
            } catch (JSONException e) {
            }
            result[i] = "null".equals(arg) ? null : arg;
        }
        return result;
    }

    private void init(String url, String userId) {
        PaygilantManager.init(getApplicationContext(), url, userId);
    }

    private Context getApplicationContext() {
        return this.cordova.getActivity().getApplicationContext();
    }

    private Activity getActivity() {
        return this.cordova.getActivity();
    }


    /**
     * Converts a JSONObject into a PGdata Checkpoint object based on the checkpoint type.
     * Each Checkpoint PGdata object has a constractor that can get a JSONObject to parse into an object.
     */
    private static CheckPoint jsonToCheckPoint(JSONObject jsonObject) throws JSONException {
        CheckPoint checkPoint;
        CheckPointType checkPointType = CheckPointType.valueOf(jsonObject.getString("type"));

        if (CheckPointType.LAUNCH.equals(checkPointType)) {
            checkPoint = new Launch(jsonObject);
        } else if (CheckPointType.GENERAL.equals(checkPointType)) {
            checkPoint = new General(jsonObject);
        } else if (CheckPointType.LOGIN.equals(checkPointType)) {
            checkPoint = new Login(jsonObject);
        } else if (CheckPointType.REGISTER.equals(checkPointType)) {
            checkPoint = new Registration(jsonObject);
        } else if (CheckPointType.ADD_PAYMENT_METHOD.equals(checkPointType)) {
            checkPoint = new AddPaymentMethod(jsonObject);
        } else if (CheckPointType.TRANSACTION.equals(checkPointType)) {
            checkPoint = new Transaction(jsonObject);
        } /*else if (CheckPointType.UPDATE_DETAILS.equals(checkPointType)) {
            checkPoint = new TransactionUpdate(jsonObject);
        }*/ else {
            throw new JSONException("could not parse arguments");
        }
        return checkPoint;
    }

    private void updateCheckPointStatus(JSONArray args) throws JSONException {
        CheckPointType checkPointType = CheckPointType.valueOf(args.getString(0));
        String requestId = args.getString(1);
        CheckPointStatus checkPointStatus = CheckPointStatus.valueOf(args.getString(2));
        String transactionId = args.optString(4, null);
        PaygilantManager.getInstance(getApplicationContext()).updateCheckPointStatus(checkPointType, requestId, checkPointStatus, transactionId);
    }

    private static String[] jsonArrayToStringArray(JSONArray array) throws JSONException {
        String[] result = new String[array.length()];
        for (int i = 0; i < array.length(); i++) {
            result[i] = array.getString(i);
        }
        return result;
    }

    private static int[] jsonArrayToIntArray(JSONArray array) throws JSONException {
        int[] result = new int[array.length()];
        for (int i = 0; i < array.length(); i++) {
            result[i] = array.getInt(i);
        }
        return result;
    }
}
