package com.duben.microtribe.net;


import com.google.gson.Gson;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


public class OkhttpUtils {

    private OkHttpClient okHttpClient;
    private Gson mGson;
    private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");//mdiatype 这个需要和服务端保持一致
    private static final MediaType MEDIA_TYPE_Bytes = MediaType.parse("application/octet-stream; charset=utf-8");//mdiatype 这个需要和服务端保持一致
    public final static int Body_Type_JSON = 0;
    public final static int Body_Type_Form = 1;
    public final static int Body_Type_Bytes = 2;
    public final static int Body_Type_String = 3;

    private OkhttpUtils() {
        okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)//10秒连接超时
                .writeTimeout(60, TimeUnit.SECONDS)//10m秒写入超时
                .readTimeout(60, TimeUnit.SECONDS)//10秒读取超时
                .build();
        mGson = new Gson();
    }

    /**
     * 在调用getInstance()方法时才会去初始化mInstance
     * 实现了懒加载
     *
     * @return
     */
    public static OkhttpUtils getInstance() {
        return OkhttpUtilsHolder.mInstance;
    }

    /**
     * 静态内部类
     * 因为一个ClassLoader下同一个类只会加载一次，保证了并发时不会得到不同的对象
     */
    private static class OkhttpUtilsHolder {
        public static OkhttpUtils mInstance = new OkhttpUtils();
    }

    private Request getRequestForGet(String url, HashMap<String, String> params, Object tag, Map<String, String> headerMap) {
        if (url == null || "".equals(url)) {
            return null;
        }

        Request.Builder requestBuilder;
        if (tag != null) {
            requestBuilder = new Request.Builder()
                    .url(paramsToString(url, params))
                    .tag(tag);

        } else {
            requestBuilder = new Request.Builder()
                    .url(paramsToString(url, params));
        }

        if (headerMap != null) {
            for (String key : headerMap.keySet()) {
                requestBuilder.addHeader(key, headerMap.get(key));
            }
        }
        return requestBuilder.build();
    }

    private String paramsToString(String mUrl, HashMap<String, String> mParamsMap) {
        if (mParamsMap != null) {
            mUrl = mUrl + "?";
            for (String key : mParamsMap.keySet()) {
                mUrl = mUrl + key + "=" + mParamsMap.get(key) + "&";
            }
            return mUrl.substring(0, mUrl.length() - 1);
        } else {
            return mUrl;
        }
    }

    private Request getRequestForPost(String url, HashMap<String, String> params, byte[] bytes, Object tag, Map<String, String> headerMap, int bodyType) {
        if (url == null || "".equals(url)) {
            return null;
        }
        if (params == null) {
            params = new HashMap<>();
        }

        RequestBody body;
        Request request;
        Request.Builder requestBuilder;

        if (bodyType == Body_Type_JSON) {
            body = RequestBody.create(MEDIA_TYPE_JSON, mGson.toJson(params));
        } else if (bodyType == Body_Type_Form) {
            FormBody.Builder formBody = new FormBody.Builder();
            if (params != null) {
                for (String key : params.keySet()) {
                    formBody.add(key, params.get(key));
                }
            }
            body = formBody.build();
        } else if (bodyType == Body_Type_Bytes) {
            body = RequestBody.create(MEDIA_TYPE_Bytes, bytes);
        } else if (bodyType == Body_Type_String) {
            body = RequestBody.create(MEDIA_TYPE_Bytes, new String(bytes));
        } else {
            return null;
        }
        if (tag != null) {
            requestBuilder = new Request.Builder().url(url).post(body).tag(tag);
        } else {
            requestBuilder = new Request.Builder().url(url).post(body);
        }

        if (headerMap != null) {
            for (String key : headerMap.keySet()) {
                requestBuilder.addHeader(key, headerMap.get(key));
            }
        }
        return requestBuilder.build();
    }


    public void commonPost(String url, HashMap<String, String> params, byte[] bytes, Object tag, Map<String, String> headerMap, int bodyType, final CallBack mCallBack) {
        Request request = getRequestForPost(url, params, bytes, tag, headerMap, bodyType);
        if (request == null) return;
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(final Call call, final IOException e) {
                if (mCallBack != null) {
                    mCallBack.onError(call, e);
                }
            }

            @Override
            public void onResponse(final Call call, final Response response) {
                if (mCallBack != null) {
                    mCallBack.onSuccess(call, response);
                }
            }
        });
    }

    public void commonGet(String url, HashMap<String, String> params, Object tag, Map<String, String> headerMap, final CallBack mCallBack) {
        Request request = getRequestForGet(url, params, tag, headerMap);
        if (request == null) return;
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(final Call call, final IOException e) {
                if (mCallBack != null) {
                    mCallBack.onError(call, e);
                }
            }

            @Override
            public void onResponse(final Call call, final Response response) {
                if (mCallBack != null) {
                    mCallBack.onSuccess(call, response);
                }
            }
        });
    }

    public void getContentLength(String url, Object tag, Callback callback) {
        // 创建一个Request
        Request request = new Request.Builder()
                .url(url)
                .header("RANGE", "bytes=" + 0 + "-" + 0)
                .addHeader("Connection", "close")
                .tag(tag)
                .build();
        doAsync(request, callback);
    }

    private void doAsync(Request request, Callback callback) {
        //创建请求会话
        Call call = okHttpClient.newCall(request);
        //同步执行会话请求
        call.enqueue(callback);
    }

    public interface CallBack {
        void onError(Call call, IOException e);

        void onSuccess(Call call, Response response);
    }

}
