package com.fdkankan.modeling.receiver;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fdkankan.common.util.ComputerUtil;
import com.fdkankan.modeling.constants.RedisKey;
import com.fdkankan.modeling.constants.SysConstants;
import com.fdkankan.modeling.entity.SceneFileBuild;
import com.fdkankan.modeling.entity.ScenePro;
import com.fdkankan.modeling.entity.SceneProExt;
import com.fdkankan.modeling.feign.UserFeign;
import com.fdkankan.modeling.push.PushMessageConfig;
import com.fdkankan.modeling.service.ISceneFileBuildService;
import com.fdkankan.modeling.service.ISceneProExtService;
import com.fdkankan.modeling.service.ISceneProService;
import com.fdkankan.modeling.service.ISceneService;
import com.fdkankan.modeling.utils.DingDingUtils;
import com.fdkankan.modeling.utils.PushMsgUtil;
import com.fdkankan.mq.message.BuildSceneMqMessage;
import com.fdkankan.oss.UploadUtils;
import com.fdkankan.platform.api.vo.User;
import com.fdkankan.utils.constant.ConstantFilePath;
import com.fdkankan.utils.constant.ConstantUrl;
import com.fdkankan.utils.utils.CreateObjUtil;
import com.fdkankan.utils.utils.FileUtil;
import com.fdkankan.utils.utils.FileUtils;
import com.taobao.api.ApiException;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

import static com.fdkankan.modeling.push.PushMessageConfig.*;


@Log4j2
@Component
@ConditionalOnProperty(name = "rabbitmq.queue.enable",havingValue = "true")
public class BuildSceneReceiver implements MessageListenerConcurrently {

    @Autowired
    private ISceneService sceneService;
    @Autowired
    private ISceneProService sceneProService;
    @Autowired
    private UserFeign userFeign;
    @Autowired
    private ISceneFileBuildService sceneFileBuildService;

    @Autowired
    private ISceneProExtService sceneProExtService;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    private RestTemplate restTemplate = new RestTemplate();

    @Value("${4dkk.laserService.host}")
    private String laserHost;

    @Value("${oss.type}")
    private String ossType;

    @Value("${oss.url.prefix}")
    private String prefixAli;


    @Autowired
    private UploadUtils uploadUtils;

    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgExt,
                                                    ConsumeConcurrentlyContext consumeConcurrentlyContext) {
        if (CollectionUtils.isEmpty(msgExt)) {
            log.error("消息内容为空,退出构建,当前服务器id:{}", SysConstants.hostName);
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
        MessageExt messageExt = msgExt.get(0);
        BuildSceneMqMessage message = JSONObject.parseObject(messageExt.getBody(), BuildSceneMqMessage.class);
        log.info("开始处理消息，消息队列：{},消息内容：{}", consumeConcurrentlyContext.getMessageQueue().getTopic(),
                JSONObject.toJSONString(message));
        process(message);
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }

    public void process(BuildSceneMqMessage message) {
        final ExecutorService exec = Executors.newFixedThreadPool(1);
        Callable<String> call = (Callable<String>) () -> {
            //开始执行耗时操作
            try {
                String key = RedisKey.SCENE_BUILDING + message.getSceneNum();
                // 获取缓存锁，防止重复消费
                Long building = redisTemplate.opsForValue().increment(key, 1);
                if (building.compareTo(1L) != 0) {
                    log.error("场景正在构建中,退出构建,当前服务器id:{},参数：{}", SysConstants.hostName, JSONObject.toJSONString(message));
                } else {
                    redisTemplate.expire(key, Duration.of(SysConstants.modelTimeOut, ChronoUnit.HOURS));
                }
                //休眠2秒等待数据入库
                Thread.sleep(2000L);
                try {
                    FileUtils.writeFile("/opt/hosts/running.txt", DateUtil.formatDateTime(new Date()));
                    String tomcatLog = "scenenum:" + message.getSceneNum() + "\ntime:" + DateUtil.formatDateTime(new Date()) +
                            " action:create hostname:" + SysConstants.hostName;
                    //打开一个写文件器，构造函数中的第二个参数true表示以追加形式写文件
                    FileWriter writer = new FileWriter("/mnt/elastic_log/tomcat" + "_" + message.getSceneNum() + ".log", true);
                    writer.write(tomcatLog);
                    writer.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                buildScene(message);
                redisTemplate.delete(key);
                try {
                    FileUtils.deleteFile("/opt/hosts/running.txt");
                    String tomcatLog = "scenenum:" + message.getSceneNum() + "\ntime:" + DateUtil.formatDateTime(new Date()) +
                            " action:delete hostname:" + SysConstants.hostName;
                    //打开一个写文件器，构造函数中的第二个参数true表示以追加形式写文件
                    FileWriter writer = new FileWriter("/mnt/elastic_log/tomcat" + "_" + message.getSceneNum() + "log", true);
                    writer.write(tomcatLog);
                    writer.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
                sceneService.updateStatus(message.getSceneNum(), -1);
                BuildSceneReceiver.this.handFail("计算失败", message);
            }
            log.info("场景生成好了***");
            return "success";
        };
        Future<String> future = exec.submit(call);
        try {
            future.get(SysConstants.modelTimeOut, TimeUnit.HOURS); //任务处理超时时间设为 24个小时
        } catch (TimeoutException ex) {
            ex.printStackTrace();
            StringWriter trace=new StringWriter();
            ex.printStackTrace(new PrintWriter(trace));
            log.error("超时了");
            log.error(trace.toString());
            FileUtils.deleteFile("/opt/hosts/running.txt");
            future.cancel(true);
            handFail("计算超时",message);
        } catch (Exception e) {
            e.printStackTrace();
            StringWriter trace=new StringWriter();
            e.printStackTrace(new PrintWriter(trace));
            log.error(trace.toString());
            FileUtils.deleteFile("/opt/hosts/running.txt");
            future.cancel(true);
            handFail("计算失败",message);
        }

    }

    private void buildScene(BuildSceneMqMessage message){
        String projectNum = null;
        SceneFileBuild sceneFileBuildEntity = null;
        ScenePro scene = null;
        SceneProExt sceneProExt = null;
        try{
            if(StringUtils.equals(message.getIsStandardization(),"1")){
                //表示标定算法
                ComputerUtil.computerCalibration(message.getPath());
                return;
            }

            String unicode = message.getUnicode();
            String path = message.getPath();
            String prefix = message.getPrefix();
            String imgsName = message.getImgsName();
            projectNum = message.getSceneNum();
            String userName = message.getUserName();
            //不同的相机不同的方法
            String cameraType = message.getCameraType();
            String algorithm = message.getAlgorithm();
            String fileId = message.getFileId();
            String cameraName = message.getCameraName();
            //0表示有4k图，1表示没有
            String resolution = message.getResolution();

            //判断调用V2还是V3版本的算法
            String buildType = ObjectUtils.isEmpty(message.getBuildType()) ? "V2" : message.getBuildType();


            log.info("执行数据库操作--前");
            sceneFileBuildEntity = sceneFileBuildService.findByFileId(fileId);
            log.info("执行数据库操作--后");

            Map<String, String> dataMap = ComputerUtil.getTypeString(cameraType, algorithm,
                    resolution);
            String splitType = dataMap.get("splitType");
            String skyboxType = dataMap.get("skyboxType");
            String dataDescribe = dataMap.get("dataDescribe");

            log.info("用的算法是："+algorithm);
            log.info("用的相机是："+ (Integer.parseInt(cameraType) < 4 ? "单球目" : "双球目（八目）"));
            Map<String,String> map = new HashMap<>();

            //该场景使用的容量
            Long space = 0L;
            //支付状态
            int payStatus = 0;
            //4表示硬件部研发的双球目相机，其余为旧版本相机
            if(Integer.parseInt(cameraType) < 3){

                for(int i = 0;i<5;++i){
                    try{
                        FileUtils.downLoadFromUrl(prefix+imgsName+"?m="+new Date().getTime(), imgsName,
                                path + File.separator + "capture");
                        FileUtils.decompress(path + File.separator + "capture" +File.separator+imgsName,
                                path + File.separator + "capture") ;
                        break;
                    }
                    catch(Exception e){
                        e.printStackTrace();
                        StringWriter trace=new StringWriter();
                        e.printStackTrace(new PrintWriter(trace));
                        log.error(trace.toString());
                        if(i<4)
                        {
                            FileUtils.deleteFile(path + File.separator + "capture" +File.separator+imgsName);
                            FileUtils.delFolder(path + File.separator + "capture" +File.separator+"images");
                        }
                        Thread.sleep(10000);
                    }
                }

                FileUtils.deleteFile(path + File.separator + "capture" +File.separator+"zip.Zip");

                String data = FileUtils.readFile(path + File.separator + "capture" +File.separator+"data.fdage");
                JSONObject dataJson = new JSONObject();
                if(data!=null){
                    dataJson = JSONObject.parseObject(data);
                    if(dataJson.containsKey("imgs")){
                        splitType = "SPLIT_V4";
                    }
                }
                //生成project.json和data.json供算法部使用
                ComputerUtil.createJson(path, splitType, skyboxType, dataDescribe, projectNum, path);
                //计算模型并返回需要上传oss的文件集合
                map = ComputerUtil.computer(projectNum, path, buildType);

                uploadUtils.uploadMulFiles(map);
                log.info("双目上完oss结束修改数据："+projectNum);
                sceneService.updateTime(projectNum, space, payStatus);
            } else {

                //休眠1秒，否则可能获取不到场景资源
                Thread.sleep(1000);
                scene = sceneProService.findBySceneNum(projectNum);
                sceneProExt = sceneProExtService.getBySceneProId(scene.getId());
                if(scene == null){
                    log.info(projectNum + ":场景不存在");
                    handFail("场景不存在",message);
                    return;
                }

                long start = System.currentTimeMillis();

                //cameraType=5为新版本双目, cameraType=6为小红屋新版本双目
                if(Integer.parseInt(cameraType) == 5 || Integer.parseInt(cameraType) == 6){
                    path = ConstantFilePath.BUILD_MODEL_PATH + unicode;

                    //下载zip包，并解压
                    FileUtils.downLoadFromUrl(prefix + "/" + imgsName + "?m=" + System.currentTimeMillis(), imgsName, path + File.separator + "capture");
                    FileUtils.decompress(path + File.separator + "capture" + File.separator + imgsName,
                            path + File.separator + "capture") ;
                    FileUtil.delFile(path + File.separator + "capture" + File.separator + imgsName);
                }else if(Integer.parseInt(cameraType) == 14 ) {
                    CreateObjUtil.ossUtilCp(ConstantFilePath.OSS_PREFIX + cameraName.replace("4DKKPRO_", "")
                                    .replace("-fdage", "").toLowerCase() + File.separator + fileId + File.separator
                                    + unicode + File.separator,
                            ConstantFilePath.BUILD_MODEL_LASER_PATH + cameraName.replace("4DKKPRO_", "")
                                    .replace("-fdage", "").toLowerCase() + File.separator + fileId + File.separator
                                    + unicode + File.separator + "capture");
                    path = ConstantFilePath.BUILD_MODEL_LASER_PATH + cameraName.replace("4DKKPRO_", "").replace("-fdage", "").toLowerCase() + File.separator + fileId + File.separator + unicode;
                } else if(Integer.parseInt(cameraType) >= 4 ) {
                    CreateObjUtil.ossUtilCp(ConstantFilePath.OSS_PREFIX + cameraName.replace("4DKKPRO_", "")
                            .replace("-fdage", "").toLowerCase() + File.separator + fileId + File.separator
                            + unicode + File.separator,
                            ConstantFilePath.BUILD_MODEL_PATH + cameraName.replace("4DKKPRO_", "")
                                    .replace("-fdage", "").toLowerCase() + File.separator + fileId + File.separator
                                    + unicode + File.separator + "capture");
                    path = ConstantFilePath.BUILD_MODEL_PATH + cameraName.replace("4DKKPRO_", "").replace("-fdage", "").toLowerCase() + File.separator + fileId + File.separator + unicode;
                }
                String data = FileUtils.readFile(path + File.separator + "capture" +File.separator+"data.fdage");
                //获取data.fdage的内容
                JSONObject dataJson = new JSONObject();
                if(data!=null){
                    dataJson = JSONObject.parseObject(data);
                }
                //判断是否计算过资源，若计算过删除缓存
                File caches = new File(path + File.separator + "caches");
                if(caches.exists()){
                    for(File deleteFile : caches.listFiles()){
                        if(new File(path + "_images").exists()){
                            if(deleteFile.isDirectory()){
                                FileUtils.delAllFile(deleteFile.getAbsolutePath());
                            }else {
                                FileUtils.deleteFile(deleteFile.getAbsolutePath());
                            }
                        }
                        else if(!deleteFile.getAbsolutePath().contains("images")){
                            if(deleteFile.isDirectory()){
                                FileUtils.delAllFile(deleteFile.getAbsolutePath());
                            }else {
                                FileUtils.deleteFile(deleteFile.getAbsolutePath());
                            }
                        }
                    }
                }
                if(new File(path + File.separator + "results").exists()){
                    FileUtils.delAllFile(path + File.separator + "results");
                }

                //生成project.json和data.json供算法部使用
                log.info("path:" + path);

                if(dataJson.containsKey("videoVersion") && StringUtils.isNotEmpty(dataJson.getString("videoVersion")) && Integer.parseInt(dataJson.getString("videoVersion")) < 4){
                    //v2版本使用4k算法
                    skyboxType = "SKYBOX_V6";
                }

                ComputerUtil.createJson(path, splitType, skyboxType, dataDescribe, projectNum, path);
                //计算模型并返回需要上传oss的文件集合
                map = ComputerUtil.computer(projectNum, path, buildType);

                if(Integer.parseInt(cameraType) == 5 || Integer.parseInt(cameraType) == 6){
                    map.put(path + File.separator + "capture/stitch_params.txt", "data/data" + projectNum + "/stitch_params.txt");
                }
                map.put(path + File.separator + "capture/Up.xml", "data/data" + projectNum + "/Up.xml");
                map.put(path + File.separator + "capture/Up2.xml", "data/data" + projectNum + "/Up2.xml");

                if(Integer.parseInt(cameraType) == 13){
                    //转台相机
                    map.put(path + File.separator + "capture/Up.txt", "data/data" + projectNum + "/Up.txt");
                    map.put(path + File.separator + "capture/Up2.txt", "data/data" + projectNum + "/Up2.txt");
                }

                uploadUtils.uploadMulFiles(map);
                payStatus = 1;

                File spaceFile = null;
                for (String key : map.keySet()) {
                    spaceFile = new File(key);
                    if(spaceFile.exists()){
                        space += spaceFile.length();
                    }
                }

                log.info("八目上完oss结束修改数据："+projectNum);

                //获取upload中的video视频名称
                String uploadData = FileUtils.readFile(path + File.separator + "results" +File.separator+"upload.json");
                com.alibaba.fastjson.JSONObject uploadJson = null;
                JSONArray array = null;
                if(uploadData!=null) {
                    uploadJson = com.alibaba.fastjson.JSONObject.parseObject(uploadData);
                    array = uploadJson.getJSONArray("upload");
                }
                com.alibaba.fastjson.JSONObject fileJson = null;
                String fileName = "";

                //读取videos_hdr_param.json, 保存点位视频的value
                Map<String, Object> videoMap = new HashMap<>();
                String videosHdr = FileUtils.readFile(path + File.separator + "results/videos/videos_hdr_param.json");
                JSONArray videoArray = null;
                if(StringUtils.isNotEmpty(videosHdr)){
                    videoArray = com.alibaba.fastjson.JSONObject.parseObject(videosHdr).getJSONArray("hdr_param");
                }
                if(videoArray != null){
                    for(int i = 0, len = videoArray.size(); i < len; i++) {
                        videoMap.put(videoArray.getJSONObject(i).getString("name"), videoArray.getJSONObject(i).getString("value"));
                        if(videoArray.getJSONObject(i).containsKey("fov")){
                            videoMap.put(videoArray.getJSONObject(i).getString("name") + "_fov", videoArray.getJSONObject(i).getString("fov"));
                        }
                    }
                }

                //计算ts文件的大小，并拼接成json格式
                JSONArray jsonArray = new JSONArray();
                com.alibaba.fastjson.JSONObject videoJson = null;
                com.alibaba.fastjson.JSONObject videosJson = new com.alibaba.fastjson.JSONObject();
                long videoSize = 0L;
                for(int i = 0, len = array.size(); i < len; i++) {
                    fileJson = array.getJSONObject(i);
                    fileName = fileJson.getString("file");
                    if(fileJson.getIntValue("clazz") == 11 && fileName.contains(".mp4") && !fileName.contains("-ios.mp4")){
                        videoJson = new com.alibaba.fastjson.JSONObject();
                        videoJson.put("id", fileName.substring(
                                0, fileName.lastIndexOf(".")).replace("videos/", ""));

                        //如果ts文件存在，就计算ts大小
                        if(new File(path + File.separator + "results" +File.separator+ fileName.replace(".mp4", ".ts")).exists()){
                            videoSize = new File(path + File.separator + "results" +File.separator+ fileName.replace(".mp4", ".ts")).length();
                            videoJson.put("tsSize", videoSize);
                        }
                        if(videoMap.containsKey(videoJson.get("id"))){
                            videoJson.put("value", videoMap.get(videoJson.get("id")));
                        }
                        if(videoMap.containsKey(videoJson.get("id") + "_fov")){
                            videoJson.put("blend_fov", videoMap.get(videoJson.get("id") + "_fov"));
                        }else {
                            videoJson.put("blend_fov", 7);
                        }
                        jsonArray.add(videoJson);
                    }
                }

                videosJson.put("data", jsonArray);
                if(dataJson.containsKey("videoVersion") && StringUtils.isNotEmpty(dataJson.getString("videoVersion")) && Integer.parseInt(dataJson.getString("videoVersion")) >= 4){
                    videosJson.put("version", 3);
                    if("oss".equals(ossType)){
                        videosJson.put("upPath", prefixAli + "data/data" + projectNum + "/Up.xml");
                    }
                    if("s3".equals(ossType)){
                        videosJson.put("upPath", ConstantUrl.PREFIX_AWS + "data/data" + projectNum + "/Up.xml");
                    }
                    if(Integer.parseInt(cameraType) == 13){
                        //转台相机
                        videosJson.put("upPath", videosJson.getString("upPath").replace(".xml", ".txt"));
                    }
                }else {
                    videosJson.put("version", 1);
                    if("oss".equals(ossType)){
                        videosJson.put("upPath", prefixAli + "data/data" + projectNum + "/Up2.xml");
                    }
                    if("s3".equals(ossType)){
                        videosJson.put("upPath", ConstantUrl.PREFIX_AWS + "data/data" + projectNum + "/Up2.xml");
                    }

                    if(Integer.parseInt(cameraType) == 13){
                        //转台相机
                        videosJson.put("upPath", videosJson.getString("upPath").replace(".xml", ".txt"));
                    }
                }

                if(Integer.parseInt(cameraType) == 5 || Integer.parseInt(cameraType) == 6){
                    videosJson.put("version", 1);
                    if("oss".equals(ossType)){
                        videosJson.put("upPath", prefixAli + "data/data" + projectNum + "/stitch_params.txt");
                    }
                    if("s3".equals(ossType)){
                        videosJson.put("upPath", ConstantUrl.PREFIX_AWS + "data/data" + projectNum + "/stitch_params.txt");
                    }
                }

                long computeTime = (System.currentTimeMillis() - start) / 1000;
                sceneProService.updateTime(projectNum, space, payStatus, videosJson.toJSONString(), computeTime);

                //更新scene.json里面的video数据
                StringBuffer dataBuf = new StringBuffer()
                        .append("data").append(File.separator)
                        .append("data").append(projectNum)
                        .append(File.separator);
                StringBuffer dataBuffer = new StringBuffer(ConstantFilePath.SCENE_PATH).append(dataBuf.toString());
                String strsceneInfos = FileUtils.readFile(dataBuffer.toString() + "scene.json");
                com.alibaba.fastjson.JSONObject scenejson = new com.alibaba.fastjson.JSONObject();
                if(strsceneInfos!=null){
                    scenejson = com.alibaba.fastjson.JSONObject.parseObject(strsceneInfos);
                }
                scenejson.put("videos", videosJson.toJSONString());
                FileUtils.writeFile(dataBuffer.toString() + "scene.json", scenejson.toString());

                User userEntity = userFeign.findByUserName(userName);
                if(userEntity == null){
                    userFeign.updateUserUsedSpaceBySceneNum(null, projectNum);
                }else {
                    userFeign.updateUserUsedSpaceBySceneNum(userEntity.getId(), projectNum);
                }
                if (sceneFileBuildEntity != null){
                    sceneFileBuildEntity.setBuildStatus(3);
                    sceneFileBuildService.updateById(sceneFileBuildEntity);
                }

                //根据data.fdage推送计算完成的消息
                log.info("推送消息，渠道是 {}, 手机token是 {}", dataJson.get("pushChannel"), dataJson.get("pushToken"));
                if(dataJson.containsKey("pushChannel") && dataJson.containsKey("pushToken")){
                    try{
                        if(!"s3".equals(ossType)){
                            PushMessageConfig demo = null;
                            if(dataJson.getIntValue("pushChannel") == 0){

                                if(Integer.parseInt(cameraType) == 10 || Integer.parseInt(cameraType) == 13){
                                    //ios
                                    log.info("IOS_KEY:{}, IOS_SECRET:{}", IOS_KEY_Z, IOS_SECRET_Z);
                                    demo = new PushMessageConfig(IOS_KEY_Z, IOS_SECRET_Z);
                                    demo.sendIOSUnicast(dataJson.getString("pushToken"),
                                            "四维看看Minion", scene.getSceneName() + "计算完成", "您上传的" + scene.getSceneName() + "计算完成，点击查看",
                                            scene.getWebSite());
                                }else {
                                    //ios
                                    log.info("IOS_KEY:{}, IOS_SECRET:{}", IOS_KEY, IOS_SECRET);
                                    demo = new PushMessageConfig(IOS_KEY, IOS_SECRET);
                                    demo.sendIOSUnicast(dataJson.getString("pushToken"),
                                            "四维看看Pro", scene.getSceneName() + "计算完成", "您上传的" + scene.getSceneName() + "计算完成，点击查看",
                                            scene.getWebSite());
                                }

                            }else {
                                if(Integer.parseInt(cameraType) == 10 || Integer.parseInt(cameraType) == 13){
                                    //ios
                                    //安卓
                                    log.info("ANDROID_KEY:{}, ANDROID_SECRET:{}", ANDROID_KEY_Z, ANDROID_SECRET_Z);
                                    demo = new PushMessageConfig(ANDROID_KEY_Z, ANDROID_SECRET_Z);
                                    demo.sendAndroidUnicast2(dataJson.getString("pushToken"),
                                            "四维看看Minion", scene.getSceneName() + "计算完成", "您上传的" + scene.getSceneName() + "计算完成，点击查看",
                                            scene.getWebSite());
                                }else {
                                    //安卓
                                    log.info("ANDROID_KEY:{}, ANDROID_SECRET:{}", ANDROID_KEY, ANDROID_SECRET);
                                    demo = new PushMessageConfig(ANDROID_KEY, ANDROID_SECRET);
                                    demo.sendAndroidUnicast(dataJson.getString("pushToken"),
                                            "四维看看Pro", scene.getSceneName() + "计算完成", "您上传的" + scene.getSceneName() + "计算完成，点击查看",
                                            scene.getWebSite());
                                }
                            }

                        }else {
                            PushMsgUtil.googlePushMsg(dataJson.getString("pushToken"),
                                    scene.getSceneName() + "计算完成", "您上传的" + scene.getSceneName() + "计算完成，点击查看",
                                    scene.getWebSite());
                        }
                        log.info("消息推送结束！");
                    }catch (Exception e){
                        log.info("推送消息失败：");
                        e.printStackTrace();
                    }
                }

                //计算成功  激光转台相机推送
                log.info("激光转台相机 同步 请求 ");
                if(Integer.parseInt(cameraType) == 14){
                    try {
                        String title = "";
                        if(StringUtils.isNotEmpty(scene.getSceneName())){
                            title = scene.getSceneName();
                        }
                        String dataSource = sceneProExt.getDataSource();
                        String jgPath = dataSource;
                        //创建目录
                        if(dataSource.lastIndexOf("/")!=-1){
                            jgPath = jgPath + "_laserData";
                        }else{
                            jgPath = jgPath.substring(0,jgPath.length()-1) + "_laserData";
                        }

                        FileUtils.createDir(jgPath+"/extras");

                        log.info("生成 激光相机目录 " + jgPath);
                        //生成data.json
                        JSONObject jgDataJson = new JSONObject();
                        jgDataJson.put("split_type", "SPLIT_V15");
                        jgDataJson.put("skybox_type", "SKYBOX_V5");
                        jgDataJson.put("extras", null);
                        FileUtils.writeFile(jgPath + File.separator + "data.json", jgDataJson.toString());

                        CreateObjUtil.cpfile(dataSource  + "/results/laserData/cover", jgPath+"/extras/");
                        CreateObjUtil.cplaserfile(dataSource  + "/results/laserData", jgPath+File.separator);

                        //激光相机
                        String url = laserHost+"/indoor/{sceneCode}/api/init?path="
                                        + jgPath + File.separator + "laserData" + "&title="+ title
                                        + "&childName=" + cameraName + "&createTime=" + scene.getCreateTime()
                                        + "&snCode="+ cameraName;

                        if(scene.getUserId()!=null){
                            url = url + "&userId=" + scene.getUserId();
                        }

                        if(StringUtils.isNotEmpty(userName)){
                            url = url + "&phone=" + userName;
                        }

                        url = url.replace("{sceneCode}",scene.getSceneCode());
                        log.info("激光转台相机 同步 ：" + url);
                        com.alibaba.fastjson.JSONObject hotListJson =
                                com.alibaba.fastjson.JSONObject.parseObject(restTemplate.getForObject(url,String.class));
                        log.info("激光转台相机 同步结束 ：" + hotListJson);
                    }catch (Exception e){
                        e.printStackTrace();
                        handFail("激光转台相机同步失败",message);
                    }
                }
            }

            CreateObjUtil.deleteFile(path.replace(ConstantFilePath.BUILD_MODEL_PATH, "/") + "/capture");
        } catch(Exception e){
            log.error("计算大场景失败"+projectNum);
            sceneService.updateStatus(projectNum, -1);
            if (sceneFileBuildEntity != null){
                sceneFileBuildEntity.setBuildStatus(-1);
                sceneFileBuildService.updateById(sceneFileBuildEntity);
            }
            e.printStackTrace();
            StringWriter trace=new StringWriter();
            e.printStackTrace(new PrintWriter(trace));
            log.error(trace.toString());
            handFail("计算失败",message);
        }finally {
            try{
                scene = sceneProService.findBySceneNum(projectNum);
                if(scene != null){
                    com.alibaba.fastjson.JSONObject statusJson = new com.alibaba.fastjson.JSONObject();
                    //临时将-2改成1，app还没完全更新
                    int status = sceneProExt.getSceneStatus();
                    if(status == -2){
                        status = 1;
                    }else if(status == -1){
                        // 失败状态不予显示到客户端
                        status = 0;
                    }
                    statusJson.put("status", status);
                    statusJson.put("webSite", scene.getWebSite());
                    statusJson.put("sceneNum", scene.getSceneCode());
                    statusJson.put("thumb", scene.getThumb());
                    statusJson.put("payStatus", sceneProExt.getPayStatus());
                    FileUtils.writeFile(ConstantFilePath.SCENE_PATH+"data/data"+projectNum+File.separator+"status.json", statusJson.toString());
                    uploadUtils.upload(ConstantFilePath.SCENE_PATH+"data/data"+projectNum+File.separator+"status.json",
                            "data/data"+projectNum+File.separator+"status.json");

                    //上送日志
                    uploadUtils.upload(sceneProExt.getDataSource()+File.separator+"console.log",
                            "build_log/"+scene.getSceneCode()+File.separator+"console.log");


                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    private void handFail(String reason,BuildSceneMqMessage message){
        String serverPath = message.getPath().substring(0,message.getPath().lastIndexOf("/")+1).concat(message.getPrefix());
        handFail(reason,serverPath,message.getSceneNum());
    }

    private void handFail(String reason,String serverPath,String num){
        // 释放缓存锁
        redisTemplate.delete(RedisKey.SCENE_BUILDING + num);
        CompletableFuture.runAsync(() -> {
            try {
                DingDingUtils.sendMsgToDingRobot(reason,serverPath,num);
            } catch (ApiException | UnsupportedEncodingException | NoSuchAlgorithmException | InvalidKeyException apiException) {
                apiException.printStackTrace();
            }
        });
    }
}
