package com.sobot.network.http.download;

import android.content.Context;
import android.os.Build;
import android.os.Environment;

import com.sobot.network.apiUtils.SobotHttpGlobalContext;
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.request.RequestCall;
import com.sobot.network.http.task.XExecutor;
import com.sobot.network.http.utils.IOUtils;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 全局的下载管理类
 */
public class SobotDownload {
    private static SobotDownload instance;

    private String folder;                                      //下载的默认文件夹
    private SobotDownloadThreadPool threadPool;                      //下载的线程池
    private ConcurrentHashMap<String, SobotDownloadTask> taskMap;    //所有任务

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

    public interface CancelTagType {
        //聊天界面
        String SOBOT_TAG_CHATROOM = "tag_chatroom";
        //下载界面
        String SOBOT_TAG_DOWNLOAD_ACT = "tag_download_act";
    }


    private SobotDownload() {
        folder = getSDCardRootPath(SobotHttpGlobalContext.getAppContext()) + "download" + File.separator;
        IOUtils.createFolder(folder);
        threadPool = new SobotDownloadThreadPool();
        taskMap = new ConcurrentHashMap<>();

        //校验数据的有效性，防止下载过程中退出，第二次进入的时候，由于状态没有更新导致的状态错误
        SobotDownloadManager.getInstance().updateDownloading2None();
    }

    public static SobotDownloadTask request(String tag, RequestCall request) {
        Map<String, SobotDownloadTask> taskMap = SobotDownload.getInstance().getTaskMap();
        SobotDownloadTask task = taskMap.get(tag);
        if (task == null) {
            task = new SobotDownloadTask(tag, request);
            taskMap.put(tag, task);
        }
        return task;
    }

    /**
     * 从数据库中恢复任务
     */
    public static SobotDownloadTask restore(SobotProgress progress) {
        Map<String, SobotDownloadTask> taskMap = SobotDownload.getInstance().getTaskMap();
        SobotDownloadTask task = taskMap.get(progress.tag);
        if (task == null) {
            task = new SobotDownloadTask(progress);
            taskMap.put(progress.tag, task);
        }
        return task;
    }

    /**
     * 从数据库中恢复任务
     */
    public static List<SobotDownloadTask> restore(List<SobotProgress> progressList) {
        Map<String, SobotDownloadTask> taskMap = SobotDownload.getInstance().getTaskMap();
        List<SobotDownloadTask> tasks = new ArrayList<>();
        for (SobotProgress progress : progressList) {
            SobotDownloadTask task = taskMap.get(progress.tag);
            if (task == null) {
                task = new SobotDownloadTask(progress);
                taskMap.put(progress.tag, task);
            }
            tasks.add(task);
        }
        return tasks;
    }

    /**
     * 开始所有任务
     */
    public void startAll() {
        for (Map.Entry<String, SobotDownloadTask> entry : taskMap.entrySet()) {
            SobotDownloadTask task = entry.getValue();
            if (task == null) {
//                OkLogger.w("can't find task with tag = " + entry.getKey());
                continue;
            }
            task.start();
        }
    }

    /**
     * 暂停全部任务
     */
    public void pauseAll() {
        //先停止未开始的任务
        for (Map.Entry<String, SobotDownloadTask> entry : taskMap.entrySet()) {
            SobotDownloadTask task = entry.getValue();
            if (task == null) {
//                OkLogger.w("can't find task with tag = " + entry.getKey());
                continue;
            }
            if (task.progress.status != SobotProgress.LOADING) {
                task.pause();
            }
        }
        //再停止进行中的任务
        for (Map.Entry<String, SobotDownloadTask> entry : taskMap.entrySet()) {
            SobotDownloadTask task = entry.getValue();
            if (task == null) {
//                OkLogger.w("can't find task with tag = " + entry.getKey());
                continue;
            }
            if (task.progress.status == SobotProgress.LOADING) {
                task.pause();
            }
        }
    }

    /**
     * 删除所有任务
     */
    public void removeAll() {
        removeAll(false);
    }

    /**
     * 删除所有任务
     *
     * @param isDeleteFile 删除任务是否删除文件
     */
    public void removeAll(boolean isDeleteFile) {
        Map<String, SobotDownloadTask> map = new HashMap<>(taskMap);
        //先删除未开始的任务
        for (Map.Entry<String, SobotDownloadTask> entry : map.entrySet()) {
            SobotDownloadTask task = entry.getValue();
            if (task == null) {
//                OkLogger.w("can't find task with tag = " + entry.getKey());
                continue;
            }
            if (task.progress.status != SobotProgress.LOADING) {
                task.remove(isDeleteFile);
            }
        }
        //再删除进行中的任务
        for (Map.Entry<String, SobotDownloadTask> entry : map.entrySet()) {
            SobotDownloadTask task = entry.getValue();
            if (task == null) {
//                OkLogger.w("can't find task with tag = " + entry.getKey());
                continue;
            }
            if (task.progress.status == SobotProgress.LOADING) {
                task.remove(isDeleteFile);
            }
        }
    }

    /**
     * 设置下载目录
     */
    public String getFolder() {
        return folder;
    }

    public SobotDownload setFolder(String folder) {
        this.folder = folder;
        return this;
    }

    public void initFolder(String tmpStr) {
        setFolder(Environment.getExternalStorageDirectory()
                + File.separator + "download" + File.separator + tmpStr + File.separator);
    }

    public SobotDownloadThreadPool getThreadPool() {
        return threadPool;
    }

    public Map<String, SobotDownloadTask> getTaskMap() {
        return taskMap;
    }

    public SobotDownloadTask getTask(String tag) {
        return taskMap.get(tag);
    }

    public boolean hasTask(String tag) {
        return taskMap.containsKey(tag);
    }

    public SobotDownloadTask removeTask(String tag) {
        return taskMap.remove(tag);
    }

    public void addOnAllTaskEndListener(XExecutor.OnAllTaskEndListener listener) {
        threadPool.getExecutor().addOnAllTaskEndListener(listener);
    }

    public void removeOnAllTaskEndListener(XExecutor.OnAllTaskEndListener listener) {
        threadPool.getExecutor().removeOnAllTaskEndListener(listener);
    }

    public void unRegister(String tag) {
        Map<String, SobotDownloadTask> taskMap = SobotDownload.getInstance().getTaskMap();
        for (SobotDownloadTask task : this.taskMap.values()) {
            task.unRegister(tag);
        }
    }


    private static final String ROOT_DIR = "sobot";
    private static final String CACHE_DIR = "cache";

    public static String getRootDir(Context mContext) {
        String packageName = mContext != null ? mContext.getPackageName() : "";
        String mRootPath = Environment.getExternalStorageDirectory().getPath() + File.separator + ROOT_DIR + File.separator + encode(packageName + File.separator + "cache");
        return mRootPath;
    }

    /**
     * 获取存储位置
     *
     * @return
     */
    public static String getSDCardRootPath(Context context) {
        if (context == null) {
            SobotNetLogUtils.i("context为空：SobotHttpUtils init 没有初始化");
            return "";
        }
        String path;
        if (isExitsSdcard()) {
            //SD卡已装入
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                //  /storage/emulated/0/sobot/com.sobot.chat.sdktest/cache/
                path = getRootDir(context) + File.separator;
            } else {
                //  /storage/emulated/0/Android/data/com.sobot.chat.sdktest/files/Download/cache/
                path = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath() + File.separator + CACHE_DIR + File.separator;
            }
            SobotNetLogUtils.i("SD卡已装入 存储路径：" + path);
        } else {
            //外部存储不可用
            path = context.getFilesDir().getPath() + File.separator + "sobot";
            SobotNetLogUtils.i("外部存储不可用 存储路径：" + path);
        }
        return path;
    }

    /**
     * 检测Sdcard是否存在
     *
     * @return
     */
    public static boolean isExitsSdcard() {
        if (android.os.Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED))
            return true;
        else
            return false;
    }

    /* 如果url中有中文就把中文编译一次 */
    public static String encode(String url) {
        if (url != null) {
            Matcher matcher = Pattern.compile("[\\u4e00-\\u9fa5]").matcher(url);
            while (matcher.find()) {
                String tmp = matcher.group();
                try {
                    url = url.replaceAll(tmp, URLEncoder.encode(tmp, "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }
        return url;
    }
}
