package com.xuqm.base.file;

import com.xuqm.base.common.LogHelper;
import com.xuqm.base.common.ToolsHelper;
import com.xuqm.base.di.component.AppComponent;
import com.xuqm.base.di.manager.HttpManager;
import com.xuqm.base.repository.CommonService;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

public class FileDownloadAndUploadManager {
    private static FileDownloadAndUploadManager instance;

    public static FileDownloadAndUploadManager getInstance() {
        if (null == instance) {
            synchronized (FileDownloadAndUploadManager.class) {
                if (null == instance) {
                    instance = new FileDownloadAndUploadManager();
                }
            }
        }
        return instance;
    }

    private final AppComponent appComponent;
    protected CompositeDisposable compositeDisposable;

    private FileDownloadAndUploadManager() {
        appComponent = HttpManager.getAppComponent("https://xuqinmin.com/", new DownloadInterceptor(thisListener));
        compositeDisposable = new CompositeDisposable();
    }

    public void download(@NonNull String url, final String filePath) {
        thisListener.onStartDownload();
        Disposable d = HttpManager.getApi(appComponent, CommonService.class)
                .download(url)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .map(ResponseBody::byteStream)
                .observeOn(Schedulers.computation())
                .doOnNext(inputStream -> writeFile(inputStream, filePath))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(body -> {
                    thisListener.onFinishDownload();
                }, err -> {
                    LogHelper.e("=============>", err);
                    thisListener.onFail(err.getMessage());
                });
        compositeDisposable.add(d);
    }

    public void cancel() {
        compositeDisposable.dispose();
        compositeDisposable.clear();
    }

    public void download(@NonNull String url, final String destDir, final String fileName, final FileDownLoadObserver<File> fileDownLoadObserver) {
        Retrofit retrofit = new Retrofit.Builder()
                .client(new OkHttpClient())
                .baseUrl("https://xuqinmin.com/")
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        HttpManager.getApi(appComponent, CommonService.class)
                .download(url)
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .observeOn(Schedulers.computation())
                .map(responseBody -> fileDownLoadObserver.saveFile(responseBody, destDir, fileName))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(fileDownLoadObserver);
    }

    public void upload(@NonNull String url, @NonNull String filePath, final Map<String, String> formDataPart) {
        upload(url, new File(filePath), formDataPart);
    }

    public void upload(@NonNull String url, @NonNull File file, final Map<String, String> formDataPart) {

        RequestBody fileBody =
                RequestBody.create(MediaType.parse("application/octet-stream"), file);
        MultipartBody.Builder body = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file", file.getName(), fileBody);

        if (null != formDataPart) {
            for (String s : formDataPart.keySet()) {
                body.addFormDataPart(s, ToolsHelper.toString(formDataPart.get(s)));
            }
        }

        Disposable d = HttpManager.getApi(appComponent, CommonService.class)
                .upload(url, body.build())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(b -> {
                    LogHelper.e("=============>上传完成:::" + b);
                }, err -> {
                    LogHelper.e("=============>", err);
                });
        compositeDisposable.add(d);
    }

    /**
     * 将输入流写入文件
     *
     * @param inputString 文件流
     * @param filePath    文件地址
     */
    private void writeFile(InputStream inputString, String filePath) {

        File file = new File(filePath);
        if (file.exists()) {
            file.delete();
        }

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);

            byte[] b = new byte[1024];

            int len;
            while ((len = inputString.read(b)) != -1) {
                fos.write(b, 0, len);
            }
            inputString.close();
            fos.close();

        } catch (FileNotFoundException e) {
            thisListener.onFail("FileNotFoundException");
        } catch (IOException e) {
            thisListener.onFail("IOException");
        }

    }

    private DownloadListener listener;

    private final DownloadListener thisListener = new DownloadListener() {
        @Override
        public void onStartDownload() {
            if (null != listener)
                listener.onStartDownload();
            LogHelper.e("=========开始下载");
        }

        @Override
        public void onProgress(int progress) {
            if (null != listener)
                listener.onProgress(progress);
            LogHelper.e("=========下载进度" + progress);
        }

        @Override
        public void onFinishDownload() {

            if (null != listener)
                listener.onFinishDownload();
            LogHelper.e("=========下载完成");
        }

        @Override
        public void onFail(String errorInfo) {
            if (null != listener)
                listener.onFail(errorInfo);
            LogHelper.e("=========下载失败" + errorInfo);
        }
    };

    public void setListener(DownloadListener listener) {
        this.listener = listener;
    }
}
