package com.ycgis.macall.personalcenter.p.request;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.rs.macall.androidx.basemodel.utils.LogUtils;
import com.ycgis.macall.personalcenter.p.app.RuanseeApplication;
import com.ycgis.macall.personalcenter.p.callback.RequestCallback;
import com.ycgis.macall.personalcenter.p.rxjava.ResultObserver;
import com.ycgis.macall.personalcenter.util.ParamMap;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;

/**
 * @Author macall
 * @Create 2020/6/23 0023
 * @Describe 接口封装类
 */
public class ApiModel {
    private static final String TAG = "ApiModel";

//    /**
//     * 下载文件
//     *
//     * @param url          下载链接
//     * @param fileName     下载后文件名
//     * @param downloadInfo 需要更新的实体
//     * @param pointer      需要更新的指针
//     * @param callBack     回调监听
//     */
   /* public static void download(Resources resources, String url, final String fileName, final DownloadOV downloadInfo, final int pointer, final DownloadCallBack callBack) {
        RetrofitService.getBaseInstance()
                .downloadFile(url)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .flatMap(new Function<ResponseBody, ObservableSource<DownloadOV>>() {

                    @Override
                    public ObservableSource<DownloadOV> apply(final ResponseBody responseBody) throws Exception {
                        return Observable.create(new ObservableOnSubscribe<DownloadOV>() {
                            @Override
                            public void subscribe(ObservableEmitter<DownloadOV> emitter) throws Exception {
                                InputStream inputStream = null;
                                long total = 0;
                                long responseLength = 0;
                                FileOutputStream fos = null;
                                try {
                                    byte[] buf = new byte[2048];
                                    int len = 0;
                                    responseLength = responseBody.contentLength();
                                    inputStream = responseBody.byteStream();
                                    String fileDir = "";
//                                    if (downloadInfo.getType() == 1) {
//                                        fileDir = FileUtil.getTxlPath();
//                                    } else if (downloadInfo.getType() == 2) {
//                                        String extension = FileUtil.getFileExtension(fileName);
//                                        fileDir = ResDrawableIdHelp.getFileDir(extension);
//                                    }
                                    final File file = new File(fileDir, fileName);
                                    downloadInfo.setFile(file);
                                    downloadInfo.setFileSize(responseLength);
                                    fos = new FileOutputStream(file);
                                    int progress = 0;
                                    int lastProgress = 0;
                                    long startTime = System.currentTimeMillis(); // 开始下载时获取开始时间
                                    while ((len = inputStream.read(buf)) != -1) {
                                        fos.write(buf, 0, len);
                                        total += len;
                                        lastProgress = progress;
                                        progress = (int) (total * 100 / responseLength);
                                        long curTime = System.currentTimeMillis();
                                        long usedTime = (curTime - startTime) / 1000;
                                        if (usedTime == 0) {
                                            usedTime = 1;
                                        }
                                        long speed = (total / usedTime); // 平均每秒下载速度
                                        // 如果进度与之前进度相等，则不更新，如果更新太频繁，则会造成界面卡顿
                                        if (progress > 0 && progress != lastProgress) {
                                            downloadInfo.setSpeed(speed);
                                            downloadInfo.setProgress(progress);
                                            downloadInfo.setCurrentSize(total);
                                            emitter.onNext(downloadInfo);
                                        }
                                    }
                                    fos.flush();
                                    downloadInfo.setFile(file);
                                    emitter.onComplete();
                                } catch (Exception e) {
                                    downloadInfo.setErrorMsg(e);
                                    emitter.onError(e);
                                } finally {
                                    try {
                                        if (fos != null) {
                                            fos.close();
                                        }
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                    try {
                                        if (inputStream != null) {
                                            inputStream.close();
                                        }
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        });
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<DownloadOV>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(DownloadOV downloadInfo) {
                        callBack.onProgress(downloadInfo.getProgress(), downloadInfo.getFileSize(), downloadInfo.getSpeed());
                        callBack.onProgress(downloadInfo, pointer);

                    }

                    @Override
                    public void onError(Throwable e) {
                        callBack.onError(e, pointer);
                    }

                    @Override
                    public void onComplete() {
                        LogUtils.e(TAG, "完成");
                        downloadInfo.setDownload(1);
                        callBack.onCompleted(downloadInfo, pointer);
                    }
                });
    }

    *//*上传文件*//*
    public static void uploadFile(int pointer, File file, FileItem item, String fileType, final UploadCallBack<JsonObject> callback) {
        //设置文件设置图片的格式
        RequestBody requestBody = RequestBody.create(getMediaType(file.getName()), file);
        String str = file.getName();
        try {
            str = URLEncoder.encode(file.getName(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            str = System.currentTimeMillis() + str.substring(str.lastIndexOf("."));
        }
        Map<String, String> map = new HashMap<>();
        map.put("files", file.getName());
        map.put("fileType", fileType);

        //设置一个file文件
        MultipartBody.Part body = MultipartBody.Part.createFormData("files", str, requestBody);
//        RetrofitService.getBaseInstance()
//                .uploadFile(RuanSiApplication.getAppCacheData().getUserCode()
//                        , RuanSiApplication.getAppCacheData().getSfzh(), RuanSiApplication.getAppCacheData().getUserName(), RuanSiApplication.getAppCacheData().getZzjgDm(), body, fileType)
//                .subscribeOn(Schedulers.io())
//                .doOnSubscribe(new Consumer<Disposable>() {
//                    @Override
//                    public void accept(@io.reactivex.annotations.NonNull Disposable disposable) throws Exception {
//                        callback.onStartRequest();
//                    }
//                })
//                //获得的数据返回主线程去更新界面
//                .observeOn(AndroidSchedulers.mainThread())
//                .subscribe(new Observer<JsonObject>() {
//                    @Override
//                    public void onSubscribe(Disposable d) {
////                        LogUtils.w(TAG, "onSubscribe " + d.toString());
//                    }
//
//                    @Override
//                    public void onNext(JsonObject s) {
////                        mode.setStatus(0).setJsonResult(s.toString()).sendLog();
////                        callback.onRequestSuccess(pointer, item, s);
//                    }
//
//                    @Override
//                    public void onError(Throwable e) {
////                        callback.onRequestFailure(pointer, item, e);
////                        LogUtils.w(TAG, "onError " + e.getMessage());
//                    }
//
//                    @Override
//                    public void onComplete() {
//                    }
//                });
    }*/
    /**
     * 发起请求
     *
     * @param requestKey {@link CommonCompositeManage#addDisposable(String, Disposable)} 接口请求标识 用来管理 请求
     * @param observable 请求体
     * @param callback   接口回调
     * @param <T>        返回类型
     */
    public static <T> void requestRetry( String requestKey, Observable<T> observable, final RequestCallback<T> callback) {
        requestRetry( observable, new Observer<T>() {
            @Override
            public void onSubscribe(@NotNull Disposable d) {
                CommonCompositeManage.getInstance().addDisposable(requestKey, d);
            }

            @Override
            public void onNext(@NotNull T t) {
                CommonCompositeManage.getInstance().unDisposable(requestKey);
                callback.onRequestSuccess(t);

            }

            @Override
            public void onError(@NotNull Throwable e) {
                CommonCompositeManage.getInstance().unDisposable(requestKey);
                callback.onRequestFailure(e);
            }

            @Override
            public void onComplete() {
                CommonCompositeManage.getInstance().unDisposable(requestKey);
            }
        });

    }
    /**
     * 请求发生IO（time out） 异常时重新请求（重复3次）
     * @param observable    被观察者（请求对象）
     * @param observer      观察者（响应对象）
     * @param <T>           返回数据类型
     */
    public static <T> void requestRetry(Observable<T> observable, Observer<T> observer) {
        observable.retryWhen(new MyFunction<Observable<Throwable>, ObservableSource<?>>() {
            @Override
            public ObservableSource<?> apply(@NotNull Observable<Throwable> throwableObservable) throws Exception {
                return throwableObservable.flatMap(new MyFunction<Throwable, ObservableSource<?>>() {
                    @Override
                    public Observable<?> apply(@NotNull Throwable throwable) throws Exception {
                        // 输出异常信息
                        LogUtils.d(TAG, "发生异常 = " + throwable.toString());
                        /**
                         * 需求1：根据异常类型选择是否重试
                         * 即，当发生的异常 = 网络异常 = IO异常 才选择重试
                         */
                        if (throwable instanceof IOException) {
                            LogUtils.d(TAG, "属于IO异常，需重试");
                            /**
                             * 需求2：限制重试次数
                             * 即，当已重试次数 < 设置的重试次数，才选择重试
                             */
                            if (currentRetryCount < maxConnectCount) {
                                // 记录重试次数
                                currentRetryCount++;
                                LogUtils.d(TAG, "重试次数 = " + currentRetryCount);
                                /**
                                 * 需求2：实现重试
                                 * 通过返回的Observable发送的事件 = Next事件，从而使得retryWhen（）重订阅，最终实现重试功能
                                 *
                                 * 需求3：延迟1段时间再重试
                                 * 采用delay操作符 = 延迟一段时间发送，以实现重试间隔设置
                                 *
                                 * 需求4：遇到的异常越多，时间越长
                                 * 在delay操作符的等待时间内设置 = 每重试1次，增多延迟重试时间1s
                                 */
                                // 设置等待时间
                                waitRetryTime = currentRetryCount * 500;
                                LogUtils.d(TAG, "等待时间 =" + waitRetryTime);
                                return Observable.just(1).delay(waitRetryTime, TimeUnit.MILLISECONDS);
                            } else {
                                // 若重试次数已 > 设置重试次数，则不重试
                                // 通过发送error来停止重试（可在观察者的onError（）中获取信息）
                                return Observable.error(new Throwable("接口请求超时，请重试！"));
                            }
                        }
                        // 若发生的异常不属于I/O异常，则不重试
                        // 通过返回的Observable发送的事件 = Error事件 实现（可在观察者的onError（）中获取信息）
                        else {
                            return Observable.error(throwable);
                        }
                    }
                });
            }
        }).subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                    }
                })
                //获得的数据返回主线程去更新界面
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }

    /**
     * 发起请求
     *
     * @param requestKey {@link CommonCompositeManage#addDisposable(String, Disposable)} 接口请求标识 用来管理 请求
     * @param observable 请求体
     * @param callback   接口回调
     * @param <T>        返回类型
     */
    public static <T> void request(final String requestKey, Observable<T> observable, final RequestCallback<T> callback) {
        request(observable, new ResultObserver<T>(requestKey) {
            @Override
            protected void onNext(String identifierKey, @NotNull T data) {
                if (callback!=null){
                    callback.onRequestSuccess(data);
                }
                CommonCompositeManage.getInstance().unDisposable(identifierKey);
            }

            @Override
            public void onSubscribe(String identifierKey, @NotNull Disposable d) {
                CommonCompositeManage.getInstance().addDisposable(identifierKey, d);
            }


            @Override
            public void onError(String identifierKey, @NotNull Throwable e) {
                LogUtils.w(TAG, "onError " + e.getMessage());
                if (callback!=null){
                    callback.onRequestFailure(e);
                }
                CommonCompositeManage.getInstance().unDisposable(identifierKey);
            }

            @Override
            public void onComplete(String identifierKey) {
                CommonCompositeManage.getInstance().unDisposable(identifierKey);
            }
        }, callback);
    }

    /**
     * 发起请求
     *
     * @param observable 请求体
     * @param callback   接口回调
     * @param <T>        返回类型
     */
    public static <T> void request(Observable<T> observable, final RequestCallback<T> callback) {
        request(observable, new Observer<T>() {
            @Override
            public void onSubscribe(Disposable d) {
//                LogUtils.w(TAG, "onSubscribe " + d.toString());
            }

            @Override
            public void onNext(T s) {
                LogUtils.w(TAG, "onSubscribe " + s.toString());
                callback.onRequestSuccess(s);
            }

            @Override
            public void onError(Throwable e) {
                callback.onRequestFailure(e);
                LogUtils.w(TAG, "onError " + e.getMessage());
            }

            @Override
            public void onComplete() {
                LogUtils.w(TAG, "onComplete ");
            }
        }, callback);
    }

//    public static <T> void request(Observable<T> observable, Observer<T> observer, final RequestCallback<T> callback) {
//        observable
//                .subscribeOn(Schedulers.io())
//                .doOnSubscribe(new Consumer<Disposable>() {
//                    @Override
//                    public void accept(@io.reactivex.annotations.NonNull Disposable disposable) throws Exception {
//                        if (callback != null) {
//                            callback.onStartRequest();
//                        }
//                    }
//                })
//                //获得的数据返回主线程去更新界面
//                .observeOn(AndroidSchedulers.mainThread())
//                .subscribe(observer);
//    }
//
    public static <T> void request(Observable<T> observable, Observer<T> observer, final RequestCallback<T> callback) {
        observable.retryWhen(new MyFunction<Observable<Throwable>, ObservableSource<?>>() {
            @Override
            public ObservableSource<?> apply(@NotNull Observable<Throwable> throwableObservable) throws Exception {
                return throwableObservable.flatMap(new MyFunction<Throwable, ObservableSource<?>>() {
                    @Override
                    public Observable<?> apply(@NotNull Throwable throwable) throws Exception {
                        // 输出异常信息
                        LogUtils.d(TAG, "发生异常 = " + throwable.toString());
                        /**
                         * 需求1：根据异常类型选择是否重试
                         * 即，当发生的异常 = 网络异常 = IO异常 才选择重试
                         */

                        if (throwable instanceof IOException || throwable instanceof TimeoutException) {
                            LogUtils.d(TAG, "属于IO异常，需重试");
                            /**
                             * 需求2：限制重试次数
                             * 即，当已重试次数 < 设置的重试次数，才选择重试
                             */
                            if (currentRetryCount < maxConnectCount) {
                                // 记录重试次数
                                currentRetryCount++;
                                LogUtils.d(TAG, "重试次数 = " + currentRetryCount);
                                /**
                                 * 需求2：实现重试
                                 * 通过返回的Observable发送的事件 = Next事件，从而使得retryWhen（）重订阅，最终实现重试功能
                                 *
                                 * 需求3：延迟1段时间再重试
                                 * 采用delay操作符 = 延迟一段时间发送，以实现重试间隔设置
                                 *
                                 * 需求4：遇到的异常越多，时间越长
                                 * 在delay操作符的等待时间内设置 = 每重试1次，增多延迟重试时间1s
                                 */
                                // 设置等待时间
                                waitRetryTime = currentRetryCount * 500;
                                LogUtils.d(TAG, "等待时间 =" + waitRetryTime);
                                return Observable.just(1).delay(waitRetryTime, TimeUnit.MILLISECONDS);
                            } else {
                                // 若重试次数已 > 设置重试次数，则不重试
                                // 通过发送error来停止重试（可在观察者的onError（）中获取信息）
                                return Observable.error(new Throwable("接口请求超时，请重试！"));
                            }
                        }
                        // 若发生的异常不属于I/O异常，则不重试
                        // 通过返回的Observable发送的事件 = Error事件 实现（可在观察者的onError（）中获取信息）
                        else {
                            return Observable.error(throwable);
                        }
                    }
                });
            }
        })
                .subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(@io.reactivex.annotations.NonNull Disposable disposable) throws Exception {
                        if (callback != null) {
                            callback.onStartRequest();
                        }
                    }
                })
                //获得的数据返回主线程去更新界面
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }

    /**
     * 全部在IO线程执行，不需要切换至UI线程
     *
     * @param observable 接口
     * @param callback   接收返回结果的监听接口
     * @param <T>        返回参数泛型
     */
    public static <T> void requestIO(final String requestKey, Observable<T> observable, final RequestCallback<T> callback) {
        requestIO(observable, new ResultObserver<T>(requestKey) {
            @Override
            protected void onSubscribe(String identifierKey, @NotNull Disposable d) {
                CommonCompositeManage.getInstance().addDisposable(identifierKey,d);
            }

            @Override
            protected void onNext(String identifierKey, @NotNull T data) {
                CommonCompositeManage.getInstance().unDisposable(identifierKey);
                if (callback!=null){
                    callback.onRequestSuccess(data);
                }
            }

            @Override
            protected void onError(String identifierKey, @NotNull Throwable data) {
                if (callback!=null){
                    callback.onRequestFailure(data);
                }
                CommonCompositeManage.getInstance().unDisposable(identifierKey);
            }

            @Override
            protected void onComplete(String identifierKey) {
                CommonCompositeManage.getInstance().unDisposable(identifierKey);
            }
        }, callback);
    }

    /**
     * 全部在IO线程执行，不需要切换至UI线程
     *
     * @param observable 接口
     * @param callback   接收返回结果的监听接口
     * @param <T>        返回参数泛型
     */
    public static <T> void requestIO(Observable<T> observable, final RequestCallback<T> callback) {
        requestIO(observable, new Observer<T>() {
            @Override
            public void onSubscribe(Disposable d) {
                LogUtils.w(TAG, "onSubscribe " + d.toString());
            }

            @Override
            public void onNext(T s) {
                if (callback != null)
                    callback.onRequestSuccess(s);
            }

            @Override
            public void onError(Throwable e) {
                if (callback != null)
                    callback.onRequestFailure(e);
                LogUtils.w(TAG, "onError " + e.getMessage());
            }

            @Override
            public void onComplete() {
                LogUtils.w(TAG, "onComplete ");
            }
        }, callback);
    }

    /**
     * 全部在IO线程执行，不需要切换至UI线程
     *
     * @param observable 请求体
     * @param observer
     * @param callback   接收返回结果的监听接口
     * @param <T>        返回参数泛型
     */
    public static <T> void requestIO(Observable<T> observable, Observer<T> observer, final RequestCallback<T> callback) {
        observable
                .subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(@io.reactivex.annotations.NonNull Disposable disposable) throws Exception {
                        if (callback != null)
                            callback.onStartRequest();
                    }
                })
                //获得的数据返回主线程去更新界面
                .observeOn(Schedulers.io())
                .subscribe(observer);
    }

    /*private static MediaType getMediaType(String fileName) {
        MediaType mediaType = MediaType.parse("application/octet-stream");
        if (fileName.endsWith(".jpg")) {
            mediaType = MediaType.parse("image/jpg");
        } else if (fileName.endsWith(".png")) {
            mediaType = MediaType.parse("image/png");
        } else if (fileName.endsWith(".jpeg")) {
            mediaType = MediaType.parse("image/jpeg");
        } else if (fileName.endsWith(".mp4")) {
            mediaType = MediaType.parse("video/mp4");
        } else if (fileName.endsWith(".mp3")) {
            mediaType = MediaType.parse("audio/mpeg");
        } else if (fileName.endsWith(".json")) {
            mediaType = MediaType.parse("application/json");
        } else if (fileName.endsWith(".jar")) {
            mediaType = MediaType.parse("application/java-archive");
        } else if (fileName.endsWith(".html")) {
            mediaType = MediaType.parse("text/html");
        } else if (fileName.endsWith(".gif")) {
            mediaType = MediaType.parse("image/gif");
        }
        return mediaType;
    }*/


    /**
     * 上传统一日志，前端 无感知，不关心结果
     * @param logLevel 1 = ALL | 2 = debug | 3 = info | 4 = Warn | 5 = Error | 6 = FATAL | 7 OFF
     *                 正常日志传 3，错误日志传5，应用报错日志传 6
     * @param optType  1 = 业务日志 | 2 = 安全日志 3 = 操作日志 | 4 = 其他
     * @param content  日志内容
     */
    public static void uploadOperationLog(String logLevel, String optType, String content) {
        ParamMap map = new ParamMap();
//        map.put("sysCode", "adde349491f64c0980ce59bd882bff53");
        //个人中心日志代码
        map.put("sysCode", "b581b2a86bc10ade016bd5a74e880001");
        map.put("logType", "3");
        map.put("logLevel", logLevel);
        map.put("optUserNum", RuanseeApplication.getUserData().getUserCode());
        map.put("optUserName", RuanseeApplication.getUserData().getUserName());
        map.put("optOrgCode", RuanseeApplication.getUserData().getDeptCode());
        map.put("optOrgName", RuanseeApplication.getUserData().getDeptName());
        map.put("optType", optType);
        map.put("content", content);
        map.put("ip", RuanseeApplication.getAppCache().getLocalIp());
        //String转RequestBody String、ByteArray、ByteString都可以用toRequestBody()
        MediaType mediaType = MediaType.Companion.parse("application/json;charset=utf-8");
        RequestBody stringBody = RequestBody.Companion.create(new Gson().toJson(map.apply()), mediaType);
        RetrofitService.getBaseInstance()
                .uploadOperationLog("http://20.90.1.142:7350/api/log/save",stringBody)
                .subscribeOn(Schedulers.io())
                //获得的数据返回主线程去更新界面
                .observeOn(Schedulers.io())
                .subscribe(new Observer<JsonObject>() {
                    @Override
                    public void onSubscribe(@NotNull Disposable d) {

                    }

                    @Override
                    public void onNext(@NotNull JsonObject jsonObject) {
                        LogUtils.w(jsonObject.toString());
                    }

                    @Override
                    public void onError(@NotNull Throwable e) {
                        LogUtils.e(e.getMessage());
                    }

                    @Override
                    public void onComplete() {

                    }
                });

    }
}
