package com.sobot.network.http.upload;

import android.text.TextUtils;
import android.util.Log;

import com.sobot.network.http.SobotOkHttpUtils;
import com.sobot.network.http.db.SobotDownloadManager;
import com.sobot.network.http.log.SobotNetLogUtils;
import com.sobot.network.http.model.SobotProgress;
import com.sobot.network.http.model.UploadFileResult;
import com.sobot.network.http.request.ProgressRequestBody;
import com.sobot.network.http.request.RequestCall;
import com.sobot.network.http.task.PriorityRunnable;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

import okhttp3.Call;
import okhttp3.Response;

/**
 * 上传任务类
 */
public class SobotUploadTask<T> implements Runnable {
    private static final String TAG = "SobotUploadTask";

    public SobotProgress progress;
    public Map<Object, SobotUploadListener> listeners;
    private ThreadPoolExecutor executor;
    private PriorityRunnable priorityRunnable;

    public SobotUploadTask(String tag, RequestCall request) {
//        HttpUtils.checkNotNull(tag, "tag == null");
        progress = new SobotProgress();
        progress.tag = tag;
        progress.isUpload = true;
//        progress.url = request.getOkHttpRequest().getBaseUrl();
        progress.status = SobotProgress.NONE;
        progress.totalSize = -1;
        progress.request = request;

        executor = SobotUpload.getInstance().getThreadPool().getExecutor();
        listeners = new HashMap<>();
    }

    public SobotUploadTask(SobotProgress progress) {
//        HttpUtils.checkNotNull(progress, "progress == null");
        this.progress = progress;
        executor = SobotUpload.getInstance().getThreadPool().getExecutor();
        listeners = new HashMap<>();
    }

    public SobotUploadTask<T> priority(int priority) {
        progress.priority = priority;
        return this;
    }

    public SobotUploadTask<T> filePath(String filePath) {
        if (filePath != null && !TextUtils.isEmpty(filePath.trim())) {
            progress.filePath = filePath;
        } else {
//            OkLogger.w("filePath is null, ignored!");
        }
        return this;
    }

    public SobotUploadTask<T> tmpTag(String tmpTag) {
        if (tmpTag != null && !TextUtils.isEmpty(tmpTag.trim())) {
            progress.tmpTag = tmpTag;
        } else {
//            OkLogger.w("filePath is null, ignored!");
        }
        return this;
    }

    /*public SobotUploadTask<T> save() {
        SobotDownloadManager.getInstance().replace(progress);
        return this;
    }*/

    public SobotUploadTask<T> register(SobotUploadListener listener) {
        if (listener != null) {
            listeners.put(listener.tag, listener);
        }
        return this;
    }

    public void unRegister(SobotUploadListener listener) {
//        HttpUtils.checkNotNull(listener, "listener == null");
        listeners.remove(listener.tag);
    }

    public void unRegister(String tag) {
//        HttpUtils.checkNotNull(tag, "tag == null");
        listeners.remove(tag);
    }

    public SobotUploadTask<T> start() {
//        if (SobotUpload.getInstance().getTask(progress.tag) == null || UploadManager.getInstance().get(progress.tag) == null) {
//            throw new IllegalStateException("you must call SobotUploadTask#save() before SobotUploadTask#start()！");
//        }
        if (SobotUpload.getInstance().getTask(progress.tag) == null) {
            Log.i(TAG, "you must call SobotUploadTask#save() before SobotUploadTask#start()！");
        }
        if (progress.status != SobotProgress.WAITING && progress.status != SobotProgress.LOADING) {
            postOnStart(progress);
            postWaiting(progress);
            priorityRunnable = new PriorityRunnable(progress.priority, this);
            executor.execute(priorityRunnable);
        } else {
            Log.w(TAG, "the task with tag " + progress.tag + " is already in the upload queue, current task status is " + progress.status);
        }
        return this;
    }

    public void restart() {
        pause();
        progress.status = SobotProgress.NONE;
        progress.currentSize = 0;
        progress.fraction = 0;
        progress.speed = 0;
//        UploadManager.getInstance().replace(progress);
        start();
    }

    /**
     * 暂停的方法
     */
    public void pause() {
        executor.remove(priorityRunnable);
        if (progress.status == SobotProgress.WAITING) {
            postPause(progress);
        } else if (progress.status == SobotProgress.LOADING) {
            progress.speed = 0;
            progress.status = SobotProgress.PAUSE;
        } else {
            Log.w(TAG, "only the task with status WAITING(1) or LOADING(2) can pause, current status is " + progress.status);
        }
    }

    /**
     * 删除一个任务,会删除下载文件
     */
    public SobotUploadTask<T> remove() {
        pause();
//        UploadManager.getInstance().delete(progress.tag);
        //noinspection unchecked
        SobotUploadTask<T> task = (SobotUploadTask<T>) SobotUpload.getInstance().removeTask(progress.tag);
        postOnRemove(progress);
        return task;
    }

    @Override
    public void run() {
        progress.status = SobotProgress.LOADING;
        postLoading(progress);
        final Response response;
        try {
            final RequestCall requestCall = progress.request;
            requestCall.getOkHttpRequest().uploadInterceptor(new ProgressRequestBody.UploadInterceptor() {
                @Override
                public void uploadProgress(SobotProgress innerProgress) {
                    Call call = requestCall.getCall();
                    if (call.isCanceled()) return;
                    if (progress.status != SobotProgress.LOADING) {
                        call.cancel();
                        return;
                    }
                    progress.from(innerProgress);
                    postLoading(progress);
                }
            });
            Call rawCall = requestCall.buildCall(null);
            response = rawCall.execute();
        } catch (Exception e) {
            postOnError(progress, e);
            return;
        }

        if (response.isSuccessful()) {
            String resultStr = null;
            try {
                resultStr = response.body().string();
                SobotNetLogUtils.i("uploadFile----->:" + resultStr);
                final SobotUploadModel result = SobotCommonGsonUtil.jsonToCommonModel(resultStr);
                if (result != null) {
                    if ("1".equals(result.getCode())) {
                        if (result.getData() != null) {
                            SobotUploadModelBase data = result.getData();
                            UploadFileResult tmpData = SobotCommonGsonUtil.obtainUploadFileResult(data.getMsg());
                            if (tmpData != null && !TextUtils.isEmpty(tmpData.getMsgId())) {
                                // 解析msgid
                                progress.tag = tmpData.getMsgId();
                                progress.url = tmpData.getUrl();
                                postOnFinish(progress, data);
                            } else {
                                postOnError(progress, new RuntimeException(result.getMsg()));
                            }
                        }
                    } else {
                        postOnError(progress, new RuntimeException(result.getMsg()));
                    }
                } else {
                    postOnError(progress, new RuntimeException("网络错误"));
                }
            } catch (Exception e) {
                e.printStackTrace();
                postOnError(progress, new RuntimeException("网络错误"));
            }
        } else {
            postOnError(progress, new RuntimeException(response.message()));
        }
    }

    private void postOnStart(final SobotProgress progress) {
        progress.speed = 0;
        progress.status = SobotProgress.NONE;
        updateDatabase(progress);
        SobotOkHttpUtils.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (SobotUploadListener listener : listeners.values()) {
                    listener.onStart(progress);
                }
            }
        });
    }

    private void postWaiting(final SobotProgress progress) {
        progress.speed = 0;
        progress.status = SobotProgress.WAITING;
        updateDatabase(progress);
        SobotOkHttpUtils.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (SobotUploadListener listener : listeners.values()) {
                    listener.onProgress(progress);
                }
            }
        });
    }

    private void postPause(final SobotProgress progress) {
        progress.speed = 0;
        progress.status = SobotProgress.PAUSE;
        updateDatabase(progress);
        SobotOkHttpUtils.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (SobotUploadListener listener : listeners.values()) {
                    listener.onProgress(progress);
                }
            }
        });
    }

    private void postLoading(final SobotProgress progress) {
        updateDatabase(progress);
        SobotOkHttpUtils.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (SobotUploadListener listener : listeners.values()) {
                    listener.onProgress(progress);
                }
            }
        });
    }

    private void postOnError(final SobotProgress progress, final Throwable throwable) {
        progress.speed = 0;
        progress.status = SobotProgress.ERROR;
        progress.exception = throwable;
        updateDatabase(progress);
        SobotOkHttpUtils.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (SobotUploadListener listener : listeners.values()) {
                    listener.onProgress(progress);
                    listener.onError(progress);
                }
            }
        });
    }

    private void postOnFinish(final SobotProgress progress, final SobotUploadModelBase result) {
        progress.speed = 0;
        progress.fraction = 1.0f;
        progress.status = SobotProgress.FINISH;
        updateDatabase(progress);
        //上传成功后存储地址
        SobotDownloadManager.getInstance().replace(progress);
        SobotOkHttpUtils.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (SobotUploadListener listener : listeners.values()) {
                    listener.onProgress(progress);
                    listener.onFinish(result, progress);
                }
                //删除任务
                if (!TextUtils.isEmpty(progress.tmpTag)) {
                    SobotUpload.getInstance().removeTask(progress.tmpTag);
                } else {
                    SobotUpload.getInstance().removeTask(progress.tag);
                }
            }
        });
    }

    private void postOnRemove(final SobotProgress progress) {
        updateDatabase(progress);
        SobotOkHttpUtils.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (SobotUploadListener listener : listeners.values()) {
                    listener.onRemove(progress);
                }
                listeners.clear();
            }
        });
    }

    private void updateDatabase(SobotProgress progress) {
//        ContentValues contentValues = SobotProgress.buildUpdateContentValues(progress);
//        UploadManager.getInstance().update(contentValues, progress.tag);
    }
}
