package com.app.http;

import android.app.Activity;
import android.util.ArrayMap;

import com.alibaba.fastjson.JSON;
import com.blankj.utilcode.util.ActivityUtils;
import com.blankj.utilcode.util.BusUtils;
import com.blankj.utilcode.util.GsonUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.blankj.utilcode.util.TimeUtils;
import com.blankj.utilcode.util.ToastUtils;

import org.xutils.common.Callback;
import org.xutils.http.RequestParams;
import org.xutils.x;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Http {
    //============样式属性===================
    public final static int LOAD_HIDE = 0x0;
    public final static int LOAD_SHOW = 0x1;
    public final static int LOAD_FIXED_SHOW = 0x12;
    public final static int ERROR_TOAST = 0x2;
    public final static int ERROR_DIALOG = 0x3;
    public final static int ERROR_HIDE = 0x4;
    public final static int ONLY_RETRY = 0;
    public final static int CANCEL_AND_RETRY = 1;
    public final static int FINISH_AND_RETRY = 2;
    private final Map<String, Object> params;    private static List<Callback.Cancelable> cancelableList = getCancelList();
    private String url;
    private int timeout = 30 * 1000;
    private LoadingDialog dialog;
    private boolean isBindLife = true;
    private Callback.Cancelable cancelable;
    private Map<String, String> headMap;
    //样式配置
    private int loadStyle = LOAD_SHOW; //默认显示网络加载框
    private int errorStyle = ERROR_TOAST; //失败后展示的样式
    private int retryStyle = CANCEL_AND_RETRY;//超时弹窗样式
    private int retryCount = 0;//超时次数 默认不重试
    //======================================
    private boolean headerOther;
    public Http() {
        params = new ArrayMap<>();
    }

    public static Http getInstance() {
        return new Http();
    }

    public static void clean() {
        if (cancelableList == null || cancelableList.size() == 0) return;
        for (Callback.Cancelable cancelable : cancelableList) {
            if (!cancelable.isCancelled()) {
                cancelable.cancel();
            }
        }
        cancelableList.clear();
    }

    private static List<Callback.Cancelable> getCancelList() {
        if (cancelableList == null) {
            cancelableList = new ArrayList<>();
        }
        return cancelableList;
    }

    public static void addCancel(Callback.Cancelable cancelable) {
        if (cancelableList != null) {
            cancelableList.add(cancelable);
        }
    }

    public static Map<String, Object> setSimpleParams(String key, String value) {
        Map<String, Object> map = new HashMap<>();
        map.put(key, value);
        return map;
    }

    public static <T> T parser(String json, Type clz) {
        return JSON.parseObject(json, clz);
    }

    public Http setUrlPath(String url, String path) {
        this.url = url + path;
        return this;
    }

    public Http setTimeout(int timeout) {
        this.timeout = timeout * 1000;
        return this;
    }

    public Http setParams(Map<String, Object> maps) {
        params.putAll(maps);
        return this;
    }

    public Http setHeaderOther(boolean headerOther) {
        this.headerOther = headerOther;
        return this;
    }

    public Http setErrorStyle(int errorStyle) {
        this.errorStyle = errorStyle;
        return this;
    }

    public Http setLoadStyle(int loadStyle) {
        this.loadStyle = loadStyle;
        return this;
    }

    public Http setRetryCount(int retryCount) {
        this.retryCount = retryCount;
        return this;
    }

    public Http setRetryStyle(int retryStyle) {
        this.retryStyle = retryStyle;
        return this;
    }

    public Http setBindLife(boolean bindLife) {
        this.isBindLife = bindLife;
        return this;
    }

    public Http setHeader(String key, String value) {
        if (headMap == null) {
            headMap = new HashMap<>();
        }
        headMap.put(key, value);
        return this;
    }

    private RequestParams setHeaderMap(RequestParams request) {
        request.addHeader("Content-Type", "application/json");
        request.addHeader("Connection", "keep-alive");
        request.addHeader("version", APPConfig.APP_VERSION);
        request.addHeader("packageName", APPConfig.APP_PACKAGE_NAME);
        request.addHeader("time", TimeUtils.getNowMills() + "");

        return request;
    }

    private RequestParams setHeaderOtherMap(RequestParams request) {
        request.addHeader("Connection", "keep-alive");
        request.addHeader("Accept-Encoding", "identity");
        return request;
    }

    public void showLoading() {
        try {
            if (ThreadUtils.isMainThread()) {
                Activity activity = ActivityUtils.getTopActivity();
                if (!ActivityUtils.isActivityAlive(activity)) {
                    return;
                }

                if (dialog == null) {
                    dialog = new LoadingDialog(activity);
                }

                if (!activity.isFinishing() && !dialog.isShowing()) {
                    if (loadStyle == LOAD_SHOW) {
                        dialog.setOnDismissListener(dialogInterface -> cancelable.cancel());
                        dialog.show();
                    } else if (loadStyle == LOAD_FIXED_SHOW) {
                        dialog.setCancelable(false);
                        dialog.setCanceledOnTouchOutside(false);
                        dialog.show();
                    }
                }


            } else {
                ThreadUtils.runOnUiThread(() -> {
                    Activity activity = ActivityUtils.getTopActivity();
                    if (!ActivityUtils.isActivityAlive(activity)) {
                        return;
                    }

                    if (dialog == null) {
                        dialog = new LoadingDialog(activity);
                    }

                    if (!activity.isFinishing() && !dialog.isShowing()) {
                        if (loadStyle == LOAD_SHOW) {
                            dialog.setOnDismissListener(dialogInterface -> cancelable.cancel());
                            dialog.show();
                        } else if (loadStyle == LOAD_FIXED_SHOW) {
                            dialog.setCancelable(false);
                            dialog.setCanceledOnTouchOutside(false);
                            dialog.show();
                        }
                    }

                });
            }
        } catch (Exception e) {
            LogUtils.e(e);
        }
    }

    public void hideLoading() {
        if (dialog != null) {
            if (ThreadUtils.isMainThread()) {
                dialog.dismiss();
            } else {
                ThreadUtils.runOnUiThread(() -> {
                    dialog.dismiss();
                });
            }
        }
    }

    private void showError(String msg) {
        switch (errorStyle) {
            case ERROR_DIALOG:
                ToastUtils.showLong(msg);
                break;
            case ERROR_TOAST:
                ToastUtils.showLong(msg);
            default:
                LogUtils.d(msg);
                break;
        }
    }

    public <T> void get(HttpCallBack<T> callBack) {
        showLoading();

        RequestParams request = headerOther ? setHeaderOtherMap(new RequestParams(url)) : setHeaderMap(new RequestParams(url));

        for (Map.Entry<String, Object> entry : params.entrySet()) {
            request.addQueryStringParameter(entry.getKey(), entry.getValue());
        }
        request.setReadTimeout(timeout);
        request.setConnectTimeout(timeout);
        request.setMaxRetryCount(retryCount);

        cancelable = x.http().get(request, new Callback.CommonCallback<BaseBean>() {
            @Override
            public void onSuccess(BaseBean result) {
                if (result.getSuccess()) {
                    Type mySuperclass = callBack.getClass().getGenericSuperclass();
                    Type tType = ((ParameterizedType) mySuperclass).getActualTypeArguments()[0];
                    T model;

                    if (result.getData() == null && tType.equals(BaseBean.class)) {
                        callBack.onNext((T) result);
                        return;
                    }

                    try {
                        model = Http.parser(result.getData(), tType);
                    } catch (Exception e) {
                        model = GsonUtils.fromJson(result.getData(), tType);
                    }
                    callBack.onNext(model);
                } else {
                    showError(result.getMsg());
                    callBack.onFail(result);
                }
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                LogUtils.d(ex.getMessage());
                callBack.onError(ex);
            }

            @Override
            public void onCancelled(CancelledException cex) {
                LogUtils.e(cex);
            }

            @Override
            public void onFinished() {
                hideLoading();
            }
        });

        if (isBindLife) cancelableList.add(cancelable);
    }

    public <T> void post(HttpCallBack<T> callBack) {
        showLoading();
        RequestParams request = headerOther ? setHeaderOtherMap(new RequestParams(url)) : setHeaderMap(new RequestParams(url));

        if (headMap != null) {
            for (Map.Entry<String, String> head : headMap.entrySet()) {
                request.addHeader(head.getKey(), head.getValue());
            }
        }

        for (Map.Entry<String, Object> entry : params.entrySet()) {
            request.addBodyParameter(entry.getKey(), entry.getValue());
        }
        request.setReadTimeout(timeout);
        request.setConnectTimeout(timeout);
        request.setMaxRetryCount(retryCount);

        cancelable = x.http().post(request, new Callback.CommonCallback<BaseBean>() {
            @Override
            public void onSuccess(BaseBean result) {
                if (result.getSuccess()) {
                    Type mySuperclass = callBack.getClass().getGenericSuperclass();
                    Type tType = ((ParameterizedType) mySuperclass).getActualTypeArguments()[0];
                    T model;

                    if (result.getData() == null && tType.equals(BaseBean.class)) {
                        callBack.onNext((T) result);
                        return;
                    }

                    try {
                        model = Http.parser(result.getData(), tType);
                    } catch (Exception e) {
                        model = GsonUtils.fromJson(result.getData(), tType);
                    }
                    callBack.onNext(model);
                } else {
                    showError(result.getMsg());
                    callBack.onFail(result);
                }
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                LogUtils.d(ex.getMessage());
                if (callBack != null)
                    callBack.onError(ex);
            }

            @Override
            public void onCancelled(CancelledException cex) {
                LogUtils.e(cex);
            }

            @Override
            public void onFinished() {
                hideLoading();
            }
        });
        if (isBindLife) cancelableList.add(cancelable);
    }

    public void postTest() {
        showLoading();
        RequestParams request = headerOther ? setHeaderOtherMap(new RequestParams(url)) : setHeaderMap(new RequestParams(url));
        request.setReadTimeout(timeout);
        request.setConnectTimeout(timeout);
        request.setMaxRetryCount(retryCount);

        cancelable = x.http().post(request, new Callback.CommonCallback<String>() {
            @Override
            public void onSuccess(String result) {
                BusUtils.post("CODE", "bing : success");
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                BusUtils.post("CODE", "bing : " + ex.getMessage());
            }

            @Override
            public void onCancelled(CancelledException cex) {
                BusUtils.post("CODE", "bing : " + cex.getMessage());
            }

            @Override
            public void onFinished() {
                hideLoading();
            }
        });
    }

    public abstract static class HttpCallBack<T> {
        public abstract void onNext(T t);

        public void onFail(BaseBean t) {

        }

        public void onError(Throwable ex) {
        }
    }




}
