package tech.starwin.impl;

import com.google.gson.Gson;

import org.greenrobot.eventbus.EventBus;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import retrofit2.HttpException;
import tech.starwin.R;
import tech.starwin.LibConfig;
import tech.starwin.mvp.beans.BasicAck;
import tech.starwin.mvp.beans.ResponseErrorBody;
import tech.starwin.mvp.beans.UpdateBean;
import tech.starwin.network.Error;
import tech.starwin.utils.LogUtils;
import tech.starwin.utils.LoginManager;

/**
 * Created by SiKang on 2018/9/14.
 * HTTP请求回调
 */
public abstract class HttpObserver<T> implements Observer<T> {
    private Disposable disposable;

    public abstract void onStart();

    public abstract void onSuccess(T data);

    public abstract void onError(int code, String msg);

    public abstract void onFinish();


    @Override
    public void onSubscribe(Disposable d) {
        this.disposable = d;
        onStart();
    }

    @Override
    public void onNext(T tResult) {
        onFinish();
        onSuccess(tResult);
    }

    @Override
    public void onError(Throwable throwable) {
        onFinish();
        String msg = throwable.getMessage();
        LogUtils.d("HttpObserver", "error msg : " + msg);
        try {
            if (throwable != null) {
                if (isNetworkError(msg)) {
                    onError(Error.HTTP_ERROR, LibConfig.getContext().getString(R.string.text_net_error));
                } else if (throwable instanceof HttpException) {
                    HttpException exception = (HttpException) throwable;
                    if (!isCanHandle(exception)) {
                        String body = exception.response().errorBody().string();
                        ResponseErrorBody responseErrorBody = new Gson().fromJson(body, ResponseErrorBody.class);
                        onError(Error.SERVER_ERROR, responseErrorBody.getMessage());
                    }
                } else if (msg.contains("java.lang.IllegalStateException")) {
                    onError(Error.APP_ERROR, "Program Exception");
                } else if (msg.contains("body is null")) {
                    onSuccess(null);
                } else {
                    onError(Error.UNKNOW, msg);
                }

            }
        } catch (Throwable e) {
            onError(Error.APP_ERROR, "Error: " + msg);
        }
        if (disposable != null)
            disposable.dispose();
    }

    @Override
    public void onComplete() {
        if (disposable != null)
            disposable.dispose();
    }

    /**
     * 可预处理的错误
     */
    private boolean isCanHandle(HttpException exception) {
        switch (exception.code()) {
            case 401://Token失效
                LoginManager.get().tokenInvalid();
                return true;
//            case 403:
//                // 短信发送失败
//                onError(Error.SERVER_ERROR, LibConfig.getContext().getString(R.string.sms_code_error));
//                return true;
            case 409:
                if (exception.response().body() != null) {
                    Gson gson = new Gson();
                    // 版本更新
                    BasicAck result = gson.fromJson(exception.response().body().toString(), BasicAck.class);
                    UpdateBean updateBean = gson.fromJson(result.getData(), UpdateBean.class);
                    EventBus.getDefault().post(updateBean);
                } else {
                    EventBus.getDefault().post(new UpdateBean());
                }
                return true;
            case 412:
                // 参数缺失
                onError(Error.SERVER_ERROR, "params missing");
                return true;
            case 404:
            case 500:
                onError(Error.SERVER_ERROR, "server exception");
                return true;
        }
        return false;
    }

    /**
     * 链路错误
     */
    private boolean isNetworkError(String msg) {
        String[] errorArray = new String[]{
                "timeout",
                "java.net.ConnectException",
                "java.net.SocketTimeoutException",
                "failed",
                "Failed to connect to",
                "stream was reset",
                "Unable to resolve host",
                "SSL handshake time out",
                "time out"
        };
        for (String error : errorArray) {
            if (msg.contains(error)) {
                return true;
            }
        }
        return false;
    }

}
