package com.yuyife.okgo;

import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

import com.google.gson.Gson;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.cache.CacheEntity;
import com.lzy.okgo.cache.CacheMode;
import com.lzy.okgo.callback.Callback;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.cookie.CookieJarImpl;
import com.lzy.okgo.cookie.store.SPCookieStore;
import com.lzy.okgo.interceptor.HttpLoggingInterceptor;
import com.lzy.okgo.model.HttpHeaders;
import com.lzy.okgo.model.Progress;
import com.lzy.okgo.model.Response;
import com.lzy.okgo.request.GetRequest;
import com.lzy.okgo.request.PostRequest;
import com.lzy.okgo.request.base.Request;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

import okhttp3.OkHttpClient;

public class OkGoUtil {
    //超时时间
    public static final long APP_MILLISECONDS = 1000 * 10;
    //Header中Token的key
    public static String TOKEN_KEY = "Authorization";
    //把Token保存到SP文件中的Key
    final private static String SP_KEY_TOKEN = "sp_key_token";
    final private static String SP_KEY_TOKEN_TIME = "sp_key_token_time";

    final private static String SP_KEY_USERINFO = "userinfo";

    public static String getYkId() {
        String ykid = "uk_" + (int) ((Math.random() * 9 + 1) * 100000);
        return ykid;
    }

    //保存Token
    public static void setToken(String token, String time) {
        if (application == null) return;
        SharedPreferences sp = application.getSharedPreferences(OkGoUtil.class.getSimpleName(), Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString(SP_KEY_TOKEN, token);
        editor.putString(SP_KEY_TOKEN_TIME, time);
        editor.apply();
        editor.commit();
    }

    //获取已有的Token
    public static String getToken() {
        if (application != null) {
            SharedPreferences sp = application.getSharedPreferences(OkGoUtil.class.getSimpleName(), Context.MODE_PRIVATE);
            return sp.getString(SP_KEY_TOKEN, null);
        }
        return null;
    }

    //获取Token登录时间
    public static String getTime() {
        if (application != null) {
            SharedPreferences sp = application.getSharedPreferences(OkGoUtil.class.getSimpleName(), Context.MODE_PRIVATE);
            return sp.getString(SP_KEY_TOKEN_TIME, null);
        }
        return null;
    }

    /**
     * 清空Token
     */
    public static void clearToken() {
        if (application == null)
            return;
        SharedPreferences sp = application.getSharedPreferences(OkGoUtil.class.getSimpleName(), Context.MODE_PRIVATE);
        sp.edit().clear().commit();
    }

    @SuppressLint("StaticFieldLeak")
    public static Context application = null;
    private static boolean addToken = false;

    public static void initOkGo(Application app, boolean addToken) {
        if (app == null) return;
        OkGoUtil.application = app;
        OkGoUtil.addToken = addToken;
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(OkGoUtil.class.getSimpleName());
        //log打印级别，决定了log显示的详细程度
        loggingInterceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY);
        //log颜色级别，决定了log在控制台显示的颜色
        loggingInterceptor.setColorLevel(Level.INFO);
        builder.addInterceptor(loggingInterceptor);

        //全局的读取超时时间  基于前面的通道建立完成后，客户端终于可以向服务端发送数据了
        builder.readTimeout(OkGoUtil.APP_MILLISECONDS, TimeUnit.MILLISECONDS);
        //全局的写入超时时间  服务器发回消息，可是客户端出问题接受不到了
        builder.writeTimeout(OkGoUtil.APP_MILLISECONDS, TimeUnit.MILLISECONDS);
        //全局的连接超时时间  http建立通道的时间
        builder.connectTimeout(OkGoUtil.APP_MILLISECONDS, TimeUnit.MILLISECONDS);

        //使用sp保持cookie，如果cookie不过期，则一直有效
        builder.cookieJar(new CookieJarImpl(new SPCookieStore(app)));
        //使用数据库保持cookie，如果cookie不过期，则一直有效
        //builder.cookieJar(new CookieJarImpl(new DBCookieStore(this)));
        //使用内存保持cookie，app退出后，cookie消失
        //builder.cookieJar(new CookieJarImpl(new MemoryCookieStore()));


        //  === 配置https ===
        //方法一：信任所有证书,不安全有风险
        /*HttpsUtils.SSLParams sslParams1 = HttpsUtils.getSslSocketFactory();
        //方法二：自定义信任规则，校验服务端证书
        HttpsUtils.SSLParams sslParams2 = HttpsUtils.getSslSocketFactory(new SafeTrustManager());
        //方法三：使用预埋证书，校验服务端证书（自签名证书）
        HttpsUtils.SSLParams sslParams3 = HttpsUtils.getSslSocketFactory(getAssets().open("srca.cer"));
        //方法四：使用bks证书和密码管理客户端证书（双向认证），使用预埋证书，校验服务端证书（自签名证书）
        HttpsUtils.SSLParams sslParams4 = HttpsUtils.getSslSocketFactory(getAssets().open("xxx.bks"), "123456", getAssets().open("yyy.cer"));
        builder.sslSocketFactory(sslParams1.sSLSocketFactory, sslParams1.trustManager);
        //配置https的域名匹配规则，详细看demo的初始化介绍，不需要就不要加入，使用不当会导致https握手失败
        builder.hostnameVerifier(new SafeHostnameVerifier());*/

        OkGo okGo;
        okGo = OkGo.getInstance().init(app)                        //必须调用初始化
                .setOkHttpClient(builder.build())               //建议设置OkHttpClient，不设置将使用默认的
                .setCacheMode(CacheMode.NO_CACHE)               //全局统一缓存模式，默认不使用缓存，可以不传
                .setCacheTime(CacheEntity.CACHE_NEVER_EXPIRE)   //全局统一缓存时间，默认永不过期，可以不传
                .setRetryCount(0);                               //全局统一超时重连次数，默认为三次，那么最差的情况会请求4次(一次原始请求，三次重连请求)，不需要可以设置为0
        if (OkGoUtil.addToken) {
            //  === 请求头 和 参数的 设置 ===
            //---------这里给出的是示例代码,告诉你可以这么传,实际使用的时候,根据需要传,不需要就不传-------------//
            HttpHeaders headers = new HttpHeaders();
            headers.put(TOKEN_KEY, getToken());    //header不支持中文，不允许有特殊字符
           /* HttpParams params = new HttpParams();
            params.put("commonParamsKey1", "commonParamsValue1");     //param支持中文,直接传,不要自己编码
            params.put("commonParamsKey2", "这里支持中文参数");*/
            okGo.addCommonHeaders(headers);                     //全局公共头  Authorization：“token”
            //.addCommonParams(params);
        }
    }

    //上传文件
    public static void upload(String url, File file) {
//        特别要注意的是
//        1). 很多人会说需要在上传文件到时候，要把Content-Type修改掉，变成multipart/form-data，就像下面这样的。其实在使用OkGo的时候，只要你添加了文件，这里的的Content-Type不需要你手动设置，OkGo自动添加该请求头，同时，OkGo也不允许你修改该请求头。
//        Content-Type: multipart/form-data; boundary=f6b76bad-0345-4337-b7d8-b362cb1f9949
//        2). 如果没有文件，那么OkGo将自动使用以下请求头，同样OkGo也不允许你修改该请求头。
//        Content-Type: application/x-www-form-urlencoded
//        3). 如果你的服务器希望你在没有文件的时候依然使用multipart/form-data请求，那么可以使用.isMultipart(true)这个方法强制修改，一般来说是不需要强制的。

        Log.d(OkGoUtil.class.getSimpleName(),
                "upload():\n url:" + url + "\n param:" + file
        );
        OkGo.<String>post(url)
                .tag(url)
                .upFile(file)
                .headers(OkGoUtil.TOKEN_KEY, getToken())
                .execute(new Callback<String>() {
                    @Override
                    public void onStart(Request<String, ? extends Request> request) {

                    }

                    @Override
                    public void onSuccess(Response<String> response) {
                        Log.d(OkGoUtil.class.getSimpleName(), "upload() onSuccess:" + response.body());

                    }

                    @Override
                    public void onCacheSuccess(Response<String> response) {

                    }

                    @Override
                    public void onError(Response<String> response) {
                        Log.d(OkGoUtil.class.getSimpleName(), "upload() onError:" + response.body());

                    }

                    @Override
                    public void onFinish() {

                    }

                    @Override
                    public void uploadProgress(Progress progress) {
                        Log.d(OkGoUtil.class.getSimpleName(), "upload() uploadProgress:" + progress);

                    }

                    @Override
                    public void downloadProgress(Progress progress) {

                    }

                    @Override
                    public String convertResponse(okhttp3.Response response) throws Throwable {
                        return null;
                    }
                });
    }

    //POST请求 数据为Map 然后转换为Json
    public static void postJson(String url, Map<String, String> param, final StringCallback callback) {
        JSONObject jsonObject;
        if (param != null && param.size() > 0) {
            jsonObject = new JSONObject(param);
        } else {
            jsonObject = new JSONObject();
        }
        postJson(url, jsonObject.toString(), callback);
    }

    //POST请求 数据为Json
    public static void postJson(String url, String json, final StringCallback callback) {
        Log.d(OkGoUtil.class.getSimpleName(), "postJson():\n url:" + url + "\n param:" + json);
        PostRequest<String> request;
        request = OkGo.<String>post(url)
                .tag(url)
                .upJson(json);
        if (OkGoUtil.addToken) {
            request.headers(OkGoUtil.TOKEN_KEY, getToken());
        }
        request.execute(new StringCallback() {
            @Override
            public void onSuccess(Response<String> response) {
                if (callback != null) {
                    callback.onSuccess(response);
                }
            }

            @Override
            public void onError(Response<String> response) {
                super.onError(response);
                if (callback != null) {
                    callback.onError(response);
                }
            }

            @Override
            public void onFinish() {
                super.onFinish();
                if (callback != null) {
                    callback.onFinish();
                }
            }
        });
    }


    //GET请求 数据为Json 最后会转成Map
    public static void getJson(String url, String paramJson, final StringCallback callback) {

        Gson gson = new Gson();
        Map<String, String> map = gson.fromJson(paramJson, Map.class);
        getMap(url, map, callback);

    }

    //GET请求 数据为Map
    public static void getMap(String url, Map<String, String> param, final StringCallback callback) {
        String getUrl = "";
        if (param != null && param.size() > 0) {
            JSONObject jsonObject = new JSONObject(param);
            Log.d(OkGoUtil.class.getSimpleName(), "getJson():\n url:" + url + "\n param:" + jsonObject.toString());
            getUrl = getUrl(url, param);
        } else {
            getUrl = url;
            Log.d(OkGoUtil.class.getSimpleName(), "getJson():\n url:" + url);
        }
        GetRequest<String> request;
        request = OkGo.<String>get(getUrl)
                .tag(getUrl);
        if (OkGoUtil.addToken) {
            request.headers(OkGoUtil.TOKEN_KEY, getToken());
        }
        request.execute(new StringCallback() {
            @Override
            public void onSuccess(Response<String> response) {
                if (callback != null) {
                    callback.onSuccess(response);
                }
            }

            @Override
            public void onError(Response<String> response) {
                super.onError(response);
                if (callback != null) {
                    callback.onError(response);
                }
            }

            @Override
            public void onFinish() {
                super.onFinish();
                if (callback != null) {
                    callback.onFinish();
                }
            }
        });
    }

    /**
     * 在指定URL后面拼接参数
     *
     * @param url    网址
     * @param params get请求的Map参数
     */
    public static String getUrl(String url, Map<String, String> params) {
        // 添加url参数
        if (params != null) {
            Iterator<String> it = params.keySet().iterator();
            StringBuffer sb = null;
            while (it.hasNext()) {
                String key = it.next();
                try {
                    String value = params.get(key);
                    if (sb == null) {
                        sb = new StringBuffer();
                        sb.append("?");
                    } else {
                        sb.append("&");
                    }
                    sb.append(key);
                    sb.append("=");
                    sb.append(value);
                } catch (Exception e) {
                    //忽略
                }
            }
            url += sb.toString();
        }
        return url;
    }


    //获取某个Key的Json数组
    public static JSONArray getListToJson(String json, String key) {
        try {
            JSONObject jsonObject = new JSONObject(json);
            return jsonObject.getJSONArray(key);
        } catch (JSONException e) {
            e.printStackTrace();
            Log.d(OkGoUtil.class.getSimpleName(), "getListToJson:key" + key + "--error:" + e.getMessage());

        }
        return null;
    }

    //获取某个Key的int
    public static int getIntToJson(String json, String key) {
        try {
            JSONObject jsonObject = new JSONObject(json);
            return jsonObject.getInt(key);
        } catch (JSONException e) {
            e.printStackTrace();
            Log.d(OkGoUtil.class.getSimpleName(), "getIntToJson:key" + key + "--error:" + e.getMessage());
        }
        return 0;
    }

    //获取某个Key的String
    public static String getStringToJson(String json, String key) {
        try {
            JSONObject jsonObject = new JSONObject(json);
            return jsonObject.getString(key);
        } catch (JSONException e) {
            e.printStackTrace();
            Log.d(OkGoUtil.class.getSimpleName(), "getStringToJson:key" + key + "--error:" + e.getMessage());
        }
        return null;
    }

    //获取某个Key的Json对象
    public static JSONObject getJsonObjectToJson(String json, String key) {
        try {
            JSONObject jsonObject = new JSONObject(json);
            return jsonObject.getJSONObject(key);
        } catch (JSONException e) {
            e.printStackTrace();
            Log.d(OkGoUtil.class.getSimpleName(), "getJsonObjectToJson:key" + key + "--error:" + e.getMessage());
        }
        return null;
    }

}
