package com.indigitall.cordova.customer;

import android.content.Context;
import android.util.Log;

import com.indigitall.android.Indigitall;
import com.indigitall.android.push.callbacks.DeviceCallback;
import com.indigitall.android.commons.models.Channel;
import com.indigitall.android.commons.models.ErrorModel;
import com.indigitall.android.customer.CustomerIndigitall;
import com.indigitall.android.customer.callbacks.CustomerCallback;
import com.indigitall.android.customer.callbacks.CustomerFieldCallback;
import com.indigitall.android.customer.models.Customer;
import com.indigitall.android.customer.models.CustomerField;
import com.indigitall.android.push.models.Device;
import com.indigitall.cordova.utils.CustomerParseUtils;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

public class CordovaIndigitallCustomer extends CordovaPlugin {
    private static final String TAG = "CDVIndigitallCustomer";
    private static final String ACTION_GET_CUSTOMER = "getCustomer";
    private static final String ACTION_GET_CUSTOMER_INFORMATION = "getCustomerInformation";
    private static final String ACTION_ASSIGN_OR_UPDATE_VALUE_TO_CUSTOMER_FIELDS = "assignOrUpdateValueToCustomerFields";
    private static final String ACTION_DELETE_VALUES_FROM_CUSTOMER_FIELDS = "deleteValuesFromCustomerFields";
    private static final String ACTION_LINK = "link";
    private static final String ACTION_UNLINK = "unlink";

    private static final String ACTION_SEND_CUSTOM_EVENT = "sendCustomEvent";

    @Override
    public boolean execute(String action, JSONArray params, CallbackContext callback) throws JSONException {
        Log.d(TAG, "Action: " + action);
        Context context = cordova.getContext();
        if (ACTION_GET_CUSTOMER.equals(action)) {
            return getCustomer(context, callback);
        } else if (ACTION_GET_CUSTOMER_INFORMATION.equals(action)) {
            return getCustomerInformation(context, params, callback);
        } else if (ACTION_ASSIGN_OR_UPDATE_VALUE_TO_CUSTOMER_FIELDS.equals(action)) {
            return assignOrUpdateValueToCustomerFields(context, params, callback);
        } else if (ACTION_DELETE_VALUES_FROM_CUSTOMER_FIELDS.equals(action)) {
            return deleteValuesFromCustomerFields(context, params, callback);
        } else if (ACTION_LINK.equals(action)) {
            return link(context, params, callback);
        } else if (ACTION_UNLINK.equals(action)) {
            return unlink(context, params, callback);
        } else if (ACTION_SEND_CUSTOM_EVENT.equals(action)) {
            return sendCustomEvent(context, params, callback);
        }

        return false;
    }

    private boolean getCustomer(Context context, final CallbackContext callback) {
        CustomerIndigitall.getCustomer(context, new CustomerCallback(context) {
            @Override
            public void onError(ErrorModel errorModel) {
                callback.error(errorModel.getErrorMessage().getErrorMessage());
            }

            @Override
            public void onSuccess(Customer customer) {
                callback.success(CustomerParseUtils.jsonFromCustomer(customer));
            }
        });
        return true;
    }

    private boolean getCustomerInformation(Context context, JSONArray params, final CallbackContext callback) {
        ArrayList<String> fieldNames = CustomerParseUtils.parseArrayList(params);
        CustomerIndigitall.getCustomerInformation(context, fieldNames, new CustomerFieldCallback(context) {
            @Override
            public void onSuccess(ArrayList<CustomerField> arrayList) {
                callback.success(CustomerParseUtils.jsonFromCustomerField(arrayList));
            }

            @Override
            public void onError(ErrorModel errorModel) {
                callback.error(errorModel.getErrorMessage().getErrorMessage());
            }
        });

        return true;
    }

    private boolean assignOrUpdateValueToCustomerFields(Context context, JSONArray params,
            final CallbackContext callback) {
        JSONObject obj = new JSONObject();
        try {
            if (params.length() > 0 && params.get(0) instanceof JSONObject) {
                obj = params.getJSONObject(0);
            }
        } catch (JSONException ex) {
            callback.error(ex.getMessage());
        }
        CustomerIndigitall.updateValueToCustomerFields(context, obj, new CustomerCallback(context) {
            @Override
            public void onSuccess(Customer customer) {
                callback.success(CustomerParseUtils.jsonFromCustomer(customer));
            }

            @Override
            public void onError(ErrorModel errorModel) {
                callback.error(errorModel.getErrorMessage().getErrorMessage());
            }
        });
        return true;
    }

    private boolean deleteValuesFromCustomerFields(Context context, JSONArray params, final CallbackContext callback) {
        ArrayList<String> fieldNames = CustomerParseUtils.parseArrayList(params);
        CustomerIndigitall.deleteValuesFromCustomerFields(context, fieldNames, new CustomerCallback(context) {
            @Override
            public void onSuccess(Customer customer) {
                callback.success(CustomerParseUtils.jsonFromCustomer(customer));
            }

            @Override
            public void onError(ErrorModel errorModel) {
                callback.error(errorModel.getErrorMessage().getErrorMessage());
            }
        });
        return true;
    }

    private boolean link(Context context, JSONArray params, final CallbackContext callback) {
        String JSON_EXTERNAL_ID = "externalId";
        String JSON_CHANNEL = "channel";
        String externalId = null;
        Channel channel = Channel.PUSH;
        try {
            if (params.length() > 0 && params.get(0) instanceof JSONObject) {
                JSONObject obj = params.getJSONObject(0);
                if (obj.has(JSON_EXTERNAL_ID))
                    externalId = obj.getString(JSON_EXTERNAL_ID);
                if (obj.has(JSON_CHANNEL))
                    channel = CustomerParseUtils.parseChannel(obj.getString(JSON_CHANNEL));
            }
        } catch (JSONException ex) {
            callback.error(ex.getMessage());
        }
        Channel finalChannel = channel;
        Indigitall.logIn(context, externalId, new DeviceCallback(context) {
            @Override
            public void onSuccess(Device device) {
                CustomerIndigitall.link(context, finalChannel, new CustomerCallback(context) {
                    @Override
                    public void onSuccess(Customer customer) {
                        callback.success(CustomerParseUtils.jsonFromCustomer(customer));
                    }

                    @Override
                    public void onError(ErrorModel errorModel) {
                        callback.error(errorModel.getErrorMessage().getErrorMessage());
                    }
                });
            }

            @Override
            public void onFail(ErrorModel errorModel) {
                callback.error(errorModel.getErrorMessage().getErrorMessage());
            }
        });

        return true;
    }

    private boolean unlink(Context context, JSONArray params, final CallbackContext callback) {
        String JSON_CHANNEL = "channel";
        Channel channel = Channel.PUSH;
        try {
            if (params.length() > 0 && params.get(0) instanceof JSONObject) {
                JSONObject obj = params.getJSONObject(0);
                if (obj.has(JSON_CHANNEL))
                    channel = CustomerParseUtils.parseChannel(obj.getString(JSON_CHANNEL));
            }
        } catch (JSONException ex) {
            callback.error(ex.getMessage());
        }
        Channel finalChannel = channel;
        Indigitall.logOut(context, new DeviceCallback(context) {
            @Override
            public void onSuccess(Device device) {
                CustomerIndigitall.unlink(context, finalChannel, new CustomerCallback(context) {
                    @Override
                    public void onSuccess(Customer customer) {
                        callback.success(CustomerParseUtils.jsonFromCustomer(customer));
                    }

                    @Override
                    public void onError(ErrorModel errorModel) {
                        callback.error(errorModel.getErrorMessage().getErrorMessage());
                    }
                });
            }

            @Override
            public void onFail(ErrorModel errorModel) {
                callback.error(errorModel.getErrorMessage().getErrorMessage());
            }
        });
        return true;
    }

    private boolean sendCustomEvent(Context context, JSONArray params, final CallbackContext callback) {
        try {
            String eventCode = CustomerParseUtils.parseEventCode(params);
            JSONObject customData = CustomerParseUtils.parseCustomData(params);
            String eventId = CustomerParseUtils.parseEventId(params);
            String eventAt = CustomerParseUtils.parseEventAt(params);
            CustomerIndigitall.sendCustomEvent(context, eventCode, eventId, eventAt, customData,
                    new CustomerCallback(context) {
                        @Override
                        public void onSuccess(Customer customer) {
                            callback.success(CustomerParseUtils.jsonFromCustomer(customer));
                        }

                        @Override
                        public void onError(ErrorModel errorModel) {
                            callback.error(errorModel.getErrorMessage().getErrorMessage());
                        }
                    });
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        return true;
    }

}
