package com.kns.api;

import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.kns.R;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;

/**
 * Created by erenbekar on 1/13/16.
 */
public class ApiClient<T> {

    private static final String TAG = "mallframe";

    private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
    private static final String ACCEPT_LANGUAGE = "Accept-Language";

    private final Context context;
    private final String resourcePath;
    private final OkHttpClient client;

    private final Map<String, String> requestParameters;
    private final String currentLocale;
    private String requestBodyAsJson;

    public ApiClient(Context context, String resourcePath) {
        this.context = context;

        //internals
        this.resourcePath = resourcePath;
        this.currentLocale = "en";

        //parameters
        this.requestParameters = new HashMap<>();
        this.requestBodyAsJson = null;

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        this.client = builder.build();

    }

    public ApiClient<T> withRequestBody(Serializable data) {
        this.requestBodyAsJson = new Gson().toJson(data);
        return this;
    }

    private T getT(Type type, Request request) throws IOException, ApiException {
        Log.v(TAG, "REQUEST URL: " + request.url());
        Log.v(TAG, "REQUEST BODY: " + requestBodyAsJson);

        Response response = client.newCall(request).execute();

        Log.v(TAG, "RESPONSE RAW: " + response);

        String json = response.body().string();

        Log.v(TAG, "RESPONSE: " + json);

        if (response.isSuccessful()) {

            if (type == null) {
                return null;
            } else {

                JsonObject object = new JsonParser().parse(json).getAsJsonObject();

                if (object != null) {

                    JsonObject error = object.getAsJsonObject("error");

                    if (error != null) {
                        String message = error.getAsJsonPrimitive("msg").getAsString();
                        int code = error.getAsJsonPrimitive("code").getAsInt();
                        throw new ApiException(code, message);
                    }

                }

                return new Gson().fromJson(json, type);

            }

        } else {

            Log.d(TAG, "error: " + json);
            throw new ApiException(response.code(), context.getString(R.string.unknown_error));

        }

    }

    private String getString(Request request) throws IOException, ApiException {
        Log.v(TAG, "REQUEST URL: " + request.url());
        Log.v(TAG, "REQUEST BODY: " + requestBodyAsJson);

        Response response = client.newCall(request).execute();

        Log.v(TAG, "RESPONSE RAW: " + response);

        String json = response.body().string();

        Log.v(TAG, "RESPONSE: " + json);

        if (response.isSuccessful()) {

            JsonObject object = new JsonParser().parse(json).getAsJsonObject();

            if (object != null) {

                JsonObject error = object.getAsJsonObject("error");

                if (error != null) {
                    String message = error.getAsJsonPrimitive("msg").getAsString();
                    int code = error.getAsJsonPrimitive("code").getAsInt();
                    throw new ApiException(code, message);
                }

            }

            return json;

        } else {

            Log.d(TAG, "error: " + json);
            throw new ApiException(response.code(), json);

        }

    }

    private String getStringForJsonArray(Request request) throws IOException, ApiException {
        Log.v(TAG, "REQUEST URL: " + request.url());
        Log.v(TAG, "REQUEST BODY: " + requestBodyAsJson);

        Response response = client.newCall(request).execute();

        Log.v(TAG, "RESPONSE RAW: " + response);

        String json = response.body().string();

        Log.v(TAG, "RESPONSE: " + json);

        if (response.isSuccessful()) {

            JsonArray object = new JsonParser().parse(json).getAsJsonArray();

            if (object != null) {

                JsonObject error = object.get(0).getAsJsonObject().getAsJsonObject("error");

                if (error != null) {
                    String message = error.getAsJsonPrimitive("msg").getAsString();
                    int code = error.getAsJsonPrimitive("code").getAsInt();
                    throw new ApiException(code, message);
                }

            }

            return json;

        } else {

            Log.d(TAG, "error: " + json);
            throw new ApiException(response.code(), json);

        }

    }

    public T get(Type type) throws ApiException {

        try {

            Request request = getGetRequest();
            return getT(type, request);

        } catch (IOException e) {
            Log.e(TAG, e.getMessage(), e);
            throw new ApiException(500, "");
        }

    }


    public T post(Type type) throws ApiException {

        try {

            RequestBody body;


            Request request = getPostRequest(requestBodyAsJson == null ? null : RequestBody.create(MEDIA_TYPE_JSON, requestBodyAsJson));
            return getT(type, request);


        } catch (IOException e) {
            throw new ApiException(500, "");
        }

    }

    public String post() throws ApiException {

        try {

            Request request = getPostRequest(requestBodyAsJson == null ? null : RequestBody.create(MEDIA_TYPE_JSON, requestBodyAsJson));
            return getString(request);

        } catch (IOException e) {
            e.printStackTrace();
            Log.v(TAG, e.getMessage());
            throw new ApiException(500, "");
        }

    }

    private Request getPostRequest(RequestBody requestBody) throws IOException {

        if (requestBody != null) {

            Buffer buffer = new Buffer();
            requestBody.writeTo(buffer);

        }

        Request.Builder builder = getUnauthorizedRequest();

        builder.post(requestBody);

        return builder.build();

    }

    private Request getGetRequest() {

        Request.Builder builder = getUnauthorizedRequest();
        return builder.get().build();

    }

    private Request.Builder getUnauthorizedRequest() {

        return new Request.Builder()
                .url(getFullUrl())
                .addHeader(ACCEPT_LANGUAGE, currentLocale.toString());

    }

    @NonNull
    private String getFullUrl() {
        return resourcePath;
    }

}
