package it.near.sdk.reactions;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Parcelable;

import com.google.gson.Gson;
import com.loopj.android.http.AsyncHttpResponseHandler;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import it.near.sdk.communication.NearAsyncHttpClient;
import it.near.sdk.logging.NearLog;
import it.near.sdk.morpheusnear.Morpheus;
import it.near.sdk.recipes.NearNotifier;
import it.near.sdk.recipes.models.Recipe;

/**
 * Superclass for NearIT core-content reactions. Adds jsonAPI parsing, simple caching.
 *
 * @author cattaneostefano.
 */
public abstract class CoreReaction extends Reaction {
    private static final String TAG = "CoreReaction";
    /**
     * Gson object to serialize and de-serialize the cache.
     */
    protected static Gson gson = null;
    private SharedPreferences sp;
    private SharedPreferences.Editor editor;
    protected NearAsyncHttpClient httpClient;
    /**
     * Cache prefix based on app package name.
     */
    protected static String PACK_NAME;
    /**
     * Morpheur object for JsonAPI parsing.
     */
    protected Morpheus morpheus;

    public CoreReaction(Context mContext, NearNotifier nearNotifier) {
        super(mContext, nearNotifier);
        // static GSON object for de/serialization of objects to/from JSON
        gson = new Gson();
        PACK_NAME = mContext.getApplicationContext().getPackageName();
        setUpMorpheus();
        initSharedPreferences(getPrefSuffix());
        httpClient = new NearAsyncHttpClient(mContext);
        refreshConfig();
    }

    /**
     * Set up the jsonapi parser for parsing only related to this plugin.
     */
    private void setUpMorpheus() {
        HashMap<String, Class> classes = getModelHashMap();
        morpheus = new Morpheus();
        for (Map.Entry<String, Class> entry : classes.entrySet()) {
            morpheus.getFactory().getDeserializer().registerResourceClass(entry.getKey(), entry.getValue());
        }
    }

    /**
     * Initialize SharedPreferences.
     * The preference name is formed by our plugin name and the package name of the app, to avoid conflicts.
     *
     * @param prefsNameSuffix suffix for shared parameters
     */
    private void initSharedPreferences(String prefsNameSuffix) {
        String PREFS_NAME = PACK_NAME + prefsNameSuffix;
        sp = mContext.getSharedPreferences(PREFS_NAME, 0);
        editor = sp.edit();
    }

    /**
     * Utility to persist lists in the SharedPreferences.
     *
     * @param key
     * @param list
     */
    protected void persistList(String key, List list) {
        String persistedString = gson.toJson(list);
        NearLog.d(key, "Persist: " + persistedString);
        editor.putString(key, persistedString);
        editor.apply();
    }

    protected void showContent(String reaction_bundle, final Recipe recipe) {
        getContent(reaction_bundle, recipe, new ContentFetchListener() {
            @Override
            public void onContentFetched(Parcelable content, boolean cached) {
                if (content == null) return;
                if (recipe.isForegroundRecipe()) {
                    nearNotifier.deliverForegroundReaction(content, recipe);
                } else {
                    nearNotifier.deliverBackgroundReaction(content, recipe.getId(), recipe.getNotificationBody(), getReactionPluginName());
                }
            }

            @Override
            public void onContentFetchError(String error) {
                NearLog.d(TAG, "Content not found");
            }
        });
    }

    protected abstract void getContent(String reaction_bundle, Recipe recipe, ContentFetchListener listener);

    /**
     * Returns a String stored in SharedPreferences.
     * It was not possible to write a generic method already returning a list because of Java type erasure
     *
     * @param key
     * @return
     */
    protected String loadCachedString(String key) {
        return sp.getString(key, "");
    }

    /**
     * Return the suffix for the local cache of this specific plugin. This string will be prefixxed by the app package name to avoid collision
     * with other nearit-powered apps.
     *
     * @return the cache suffix. Use a suffix unique for the plugin.
     */
    public abstract String getPrefSuffix();

    /**
     * Returns the list of POJOs and the jsonAPI resource type string for this plugin.
     *
     * @return
     */
    protected abstract HashMap<String, Class> getModelHashMap();

    /**
     * Return the resource type.
     *
     * @return the name of the resource handled by the plugin.
     */
    protected abstract String getResTypeName();

    /**
     * Download a single request.
     *
     */
    protected abstract void requestSingleReaction(String bundleId, AsyncHttpResponseHandler responseHandler);


    public void requestSingleReaction(final String bundleId, final AsyncHttpResponseHandler responseHandler, int i) {
        NearLog.e("PUSH WAIT", "I'm waiting " + i + " millis");
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                requestSingleReaction(bundleId, responseHandler);
            }
        }, i);
    }
}

@@ -122,24 +122,50 @@
 os.Handler;%0A
+import android.os.Looper;%0A
 import andro
@@ -182,16 +182,16 @@
 elable;%0A
-
 %0Aimport 
@@ -269,16 +269,45 @@
 ndler;%0A%0A
+import org.json.JSONObject;%0A%0A
 import j
@@ -370,16 +370,61 @@
 l.Map;%0A%0A
+import cz.msebera.android.httpclient.Header;%0A
 import i
@@ -469,16 +469,78 @@
 Client;%0A
+import it.near.sdk.communication.NearJsonHttpResponseHandler;%0A
 import i
@@ -5154,21 +5154,24 @@
 , final 
-Async
+NearJson
 HttpResp
@@ -5316,16 +5316,38 @@
 Handler(
+Looper.getMainLooper()
 );%0A     
@@ -5488,31 +5488,588 @@
 ndleId, 
-responseHandler
+new NearJsonHttpResponseHandler() %7B%0A                    @Override%0A                    public void onSuccess(int statusCode, Header%5B%5D headers, JSONObject response) %7B%0A                        responseHandler.onSuccess(statusCode, headers, response);%0A                    %7D%0A%0A                    @Override%0A                    public void onFailureUnique(int statusCode, Header%5B%5D headers, Throwable throwable, String responseString) %7B%0A                        responseHandler.onFailureUnique(statusCode, headers, throwable, responseString);%0A                    %7D%0A                %7D
 );%0A     

create response handler in correct thread