package com.luticate.utils.business;

import android.content.Context;
import android.net.Uri;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.luticate.utils.dbo.LuDataAccessConfigDbo;
import com.luticate.utils.dbo.LuDbo;

import org.json.JSONObject;

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

/**
 *
 * Created by robin on 11/27/15.
 */
public class LuRequest {

    private static RequestQueue _requestQueue = null;

    public static void init(Context ctx)
    {
        _requestQueue = Volley.newRequestQueue(ctx.getApplicationContext());
    }

    protected static <T extends LuDbo> Response.Listener<String> getListener(final Class<T> type, final LuPromise<T> promise)
    {
        return new Response.Listener<String>()
        {
            @Override
            public void onResponse(String response) {
                try {
                    T dbo = type.newInstance();
                    try {
                        JSONObject json = new JSONObject(response);
                        JSONObject obj = null;
                        if (!json.isNull("Data")) {
                            obj = json.optJSONObject("Data");
                            if (obj == null) {
                                obj = new JSONObject();
                                obj.put("Value", json.opt("Data"));
                            }
                        }
                        dbo.fromJson(obj);
                        promise.resolve(dbo);
                    } catch (Exception e)
                    {
                        e.printStackTrace();
                        promise.reject(new LuPromise.LuPromiseError("Failed to parse success server response", 200));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    promise.reject(new LuPromise.LuPromiseError("Failed to initialize server response", 200));
                }
            }
        };
    }

    protected static <T extends LuDbo> Response.ErrorListener getErrorListener(final LuPromise<T> promise)
    {
        return new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                int code = 0;
                if (error != null && error.networkResponse != null)
                {
                    code = error.networkResponse.statusCode;
                }
                try
                {
                    JSONObject data = new JSONObject(new String(error.networkResponse.data));
                    promise.reject(new LuPromise.LuPromiseError(data.getString("Message"), code));
                } catch (Exception e)
                {
                    promise.reject(new LuPromise.LuPromiseError(e.getMessage(), code));
                }
                promise.reject(new LuPromise.LuPromiseError(error.toString(), code));
            }
        };
    }

    protected static <T extends LuDbo> LuPromise<T> request(final LuDataAccessConfigDbo config,
                                                            int method, Class<T> type, String url,
                                                            final HashMap<String, String> params)
    {
        LuPromise<T> promise = new LuPromise<>();
        StringRequest request = new StringRequest(method, config.getBaseUrl() + url,
                getListener(type, promise), getErrorListener(promise))
        {
            @Override
            public String getBodyContentType() {
                return "application/x-www-form-urlencoded; charset=UTF-8";
            }

            @Override
            protected Map<String, String> getParams() {
                return params;
            }

            @Override
            public Map<String, String> getHeaders() {
                return config.getHeaders();
            }
        };
        _requestQueue.add(request);
        return promise;
    }

    public static <T extends LuDbo> LuPromise<T> get(final LuDataAccessConfigDbo config, Class<T> type,
                                                     String url, final HashMap<String, String> getParams)
    {
        Uri.Builder uri = Uri.parse(url).buildUpon();
        for (String key : getParams.keySet())
        {
            uri.appendQueryParameter(key, getParams.get(key));
        }
        LuPromise<T> promise = new LuPromise<>();
        StringRequest request = new StringRequest(Request.Method.GET, config.getBaseUrl() + uri.toString(),
                getListener(type, promise), getErrorListener(promise))
        {
            @Override
            public Map<String, String> getHeaders() {
                return config.getHeaders();
            }
        };
        _requestQueue.add(request);
        return promise;
    }

    public static <T extends LuDbo> LuPromise<T> get(LuDataAccessConfigDbo config, Class<T> type,
                                                     String url)
    {
        return get(config, type, url, new HashMap<String, String>());
    }

    public static <T extends LuDbo> LuPromise<T> post(LuDataAccessConfigDbo config, Class<T> type,
                                                      String url, final HashMap<String, String> postParams)
    {
        return request(config, Request.Method.POST, type, url, postParams);
    }

    public static <T extends LuDbo> LuPromise<T> post(LuDataAccessConfigDbo config, Class<T> type,
                                                      String url)
    {
        return post(config, type, url, new HashMap<String, String>());
    }
}
