package xn.xxp.app;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import android.os.FileObserver;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.core.util.Pair;

import com.blankj.utilcode.util.ActivityUtils;
import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.GsonUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.blankj.utilcode.util.Utils;
import com.google.gson.reflect.TypeToken;
import com.njlz.event.BuildModelEvent;
import com.njlz.face.FaceUtils;
import com.njlz.smartdata.FaceBuildBean;
import com.njlz.smartdata.FaceConfig;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONObject;

import java.io.File;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import http.client.HttpTool;
import okhttp3.Response;
import xn.xxp.home.auth.ChoiceAuthActivity;
import xn.xxp.home.setting.FaceListActivity;
import xn.xxp.room.RoomTool;
import xn.xxp.room.bean.Face;
import xn.xxp.room.dao.FaceDao;

public enum SyncFaceTool {
    INSTANCE;

    private DownloadManager downloadManager;
    private long lastEventTime = 0;
    private long lastBuildTime = 0;
    private volatile boolean isBuildFaceEnd = false;
    private List<Face> faceList;
    public volatile boolean isSyncFace = false;

    SyncFaceTool() {

    }

    @WorkerThread
    public void doWork() {
        if (AppUtils.isAppDebug()) {
            SyncFaceDeBugTool.INSTANCE.doWork();
        } else {
            if (ThreadUtils.isMainThread()) {
                LogUtils.e("该方法必须在子线程调用");
                return;
            }
            Activity topActivity = ActivityUtils.getTopActivity();
            if (topActivity instanceof ChoiceAuthActivity) {
                LogUtils.d("人脸识别中,不去同步人脸!");
                return;
            }
            if (topActivity instanceof FaceListActivity) {
                LogUtils.d("正在查阅底库,不去同步人脸!");
                return;
            }
            if (isSyncFace) {
                LogUtils.d("正在同步人脸");
                return;
            }
            if (null == downloadManager) {
                downloadManager = (DownloadManager) Utils.getApp().getApplicationContext().getSystemService(Context.DOWNLOAD_SERVICE);
            }
            // 初始化
            isSyncFace = true;
            try {
                // 同步人脸
                FaceUtils.getInstance().init(Utils.getApp());
                FaceConfig faceConfig = FaceUtils.getInstance().getFaceConfig();
                LogUtils.json("底库配置", faceConfig);
                EventBus.getDefault().register(this);
                // http请求同步
                List<Pair<String, String>> faceUrlList = getLabFaceList();
                if (null != faceUrlList && !faceUrlList.isEmpty()) {
                    // 下载人脸
                    List<FaceBuildBean> faceBuildBeanList = downloadPicAndBuild(faceUrlList);
                    LogUtils.json("需要变更的人脸", faceBuildBeanList);
                    // 人脸建模
                    if (null != faceBuildBeanList && !faceBuildBeanList.isEmpty()) {
                        FaceUtils.getInstance().faceBuild(faceBuildBeanList);
                        lastBuildTime = System.currentTimeMillis();
                        // 等待人脸建模
                        while (!isBuildFaceEnd) {
                            Thread.sleep(10);
                            if (System.currentTimeMillis() - lastBuildTime > 2000) {
                                isBuildFaceEnd = true;
                            }
                        }
                    }
                    LogUtils.json(RoomTool.getInstance().faceDao().getAll());
                } else {
                    LogUtils.d("不需要下载变更人脸");
                }
                // 删除本地多余的人脸
                delRedundantFace();
                LogUtils.d("底库", FaceUtils.getInstance().getAllFaceId());
            } catch (Exception e) {
                LogUtils.e(Log.getStackTraceString(e));
            } finally {
                try {
                    // 销毁
                    EventBus.getDefault().unregister(this);
                    FaceUtils.getInstance().destroy();
                } catch (Exception e) {
                    LogUtils.e(Log.getStackTraceString(e));
                }
            }
            isSyncFace = false;
        }
    }

    private List<Pair<String, String>> getLabFaceList() {
        try {
            Response response = HttpTool.getLabFaceList();
            if (null != response && response.isSuccessful()) {
                String json = response.body().string();
                JSONObject jsonObject = new JSONObject(json);
                int code = jsonObject.getInt("code");
                if (200 == code) {
                    Type faceListType = new TypeToken<List<Face>>() {
                    }.getType();
                    faceList = GsonUtils.fromJson(jsonObject.getJSONArray("data").toString(), faceListType);

                    if (null != faceList && !faceList.isEmpty()) {
                        FaceDao faceDao = RoomTool.getInstance().faceDao();
                        @SuppressLint("SdCardPath") final String savePath = "/sdcard/facePic/";
                        FileUtils.createOrExistsDir(savePath);
                        // 1.id 2.url
                        List<Pair<String, String>> faceUrlList = new ArrayList<>();
                        List<String> allFaceIdList = FaceUtils.getInstance().getAllFaceId();
                        for (int i = 0; i < faceList.size(); i++) {
                            Face face = faceList.get(i);
                            Face sqlFace = faceDao.getById(face.getUserId());
                            if (null != sqlFace) {
                                boolean sqlInDb = false;
                                for (int j = 0; j < allFaceIdList.size(); j++) {
                                    if (allFaceIdList.get(j).equals(String.valueOf(sqlFace.getUserId()))) {
                                        sqlInDb = true;
                                    }
                                }

                                if (sqlInDb && face.getLastUpdated() <= sqlFace.getLastUpdated()) {
                                    continue;
                                }
                            }
                            faceUrlList.add(Pair.create(String.valueOf(face.getUserId()), HttpTool.checkUrl(face.getFaceUrl())));
                        }
                        return faceUrlList;
                    } else {
                        return new ArrayList<>();
                    }
                }
            }
        } catch (Exception e) {
            LogUtils.e(Log.getStackTraceString(e));
        }
        return null;
    }

    private List<FaceBuildBean> downloadPicAndBuild(List<Pair<String, String>> faceUrlList) {
        if (null == faceUrlList || faceUrlList.isEmpty()) {
            return null;
        }
        try {
            @SuppressLint("SdCardPath") final String filePathDir = "/sdcard/" + Environment.DIRECTORY_DOWNLOADS + "/facePic/";
            FileUtils.createOrExistsDir(filePathDir);
            FileUtils.deleteAllInDir(filePathDir);
            List<FaceBuildBean> faceBuildBeanList = new ArrayList<>();
            List<File> downloadList = new LinkedList<>();
            for (int i = 0; i < faceUrlList.size(); i++) {
                // 1.id 2.url
                Pair<String, String> downloadPair = faceUrlList.get(i);
                DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadPair.second));
                request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "facePic/" + downloadPair.first + ".jpg");
                request.setMimeType("image/jpeg");
                request.setVisibleInDownloadsUi(false);
                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
                downloadManager.enqueue(request);
                downloadList.add(new File(filePathDir + downloadPair.first + ".jpg"));
            }
            // 文件观察者
            FileObserver fileObserver = getFileObserver(filePathDir, downloadList);
            // 开始观察
            fileObserver.startWatching();
            lastEventTime = System.currentTimeMillis();
            // 观察者无响应2秒后 认为下载结束
            while (!downloadList.isEmpty()) {
                Thread.sleep(1000);
                if (System.currentTimeMillis() - lastEventTime > 2000) {
                    downloadList.clear();
                }
            }
            // 停止观察
            fileObserver.stopWatching();

            // 同步人脸
            List<File> facePicList = FileUtils.listFilesInDir(filePathDir);
            if (!facePicList.isEmpty()) {
                for (int i = 0; i < facePicList.size(); i++) {
                    File file = facePicList.get(i);
                    FaceBuildBean faceBuildBean = new FaceBuildBean();
                    faceBuildBean.setPicPath(file.getAbsolutePath());
                    faceBuildBean.setFaceUuid(file.getName().replace(".jpg", ""));
                    faceBuildBeanList.add(faceBuildBean);
                }
            }
            return faceBuildBeanList;
        } catch (Exception e) {
            LogUtils.e(Log.getStackTraceString(e));
        }
        return null;
    }

    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onReceive(BuildModelEvent buildModelEvent) {
        if (buildModelEvent.isDone()) {
            List<FaceBuildBean> list = FaceUtils.getInstance().getFaceResult();
            FaceDao faceDao = RoomTool.getInstance().faceDao();
            if (list != null && !list.isEmpty()) {
                for (FaceBuildBean faceBuildBean : list) {
                    if (faceBuildBean.getErrCode() != 0) {
                        LogUtils.e("建模失败", faceBuildBean.getFaceUuid(), faceBuildBean.getErrCode());
                    } else {
                        if (null != faceList && !faceList.isEmpty()) {
                            long uuid = Long.parseLong(faceBuildBean.getFaceUuid());
                            for (int i = 0; i < faceList.size(); i++) {
                                Face face = faceList.get(i);
                                if (face.getUserId() == uuid) {
                                    faceDao.insertAll(face);
                                }
                            }
                        }
                    }
                }
            }
            isBuildFaceEnd = true;
        }
        lastBuildTime = System.currentTimeMillis();
    }

    private @NonNull FileObserver getFileObserver(String filePathDir, List<File> downloadList) {
        return new FileObserver(filePathDir) {
            final Map<String, Integer> fileStateMap = new LinkedHashMap<>();

            @Override
            public void onEvent(int event, @Nullable String path) {
                lastEventTime = System.currentTimeMillis();
                if (null != path) {
                    if (event == CLOSE_WRITE) {
                        Integer count = fileStateMap.get(path);
                        if (null == count) {
                            fileStateMap.put(path, 1);
                        } else if (count >= 2) {
                            downloadList.removeIf(file -> path.equals(file.getName()));
                        } else {
                            fileStateMap.put(path, count + 1);
                        }
                    }
                }
            }
        };
    }

    /**
     * 删除本地多余的人脸
     */
    private void delRedundantFace() {
        List<String> allFaceIdList = FaceUtils.getInstance().getAllFaceId();
        FaceDao faceDao = RoomTool.getInstance().faceDao();
        if (faceList != null && allFaceIdList != null && !allFaceIdList.isEmpty()) {
            if (faceList.isEmpty()) {
                FaceUtils.getInstance().deleteAllFace();
                faceDao.clear();
            } else {
                for (int i = 0; i < allFaceIdList.size(); i++) {
                    String uuid = allFaceIdList.get(i);
                    boolean hasFace = false;
                    for (int j = 0; j < faceList.size(); j++) {
                        if (faceList.get(j).getUserId() == Long.parseLong(uuid)) {
                            hasFace = true;
                            break;
                        }
                    }
                    if (!hasFace) {
                        FaceUtils.getInstance().deleteFace(uuid);
                        faceDao.delete(Long.parseLong(uuid));
                    }
                }
            }
        }
    }
}