package com.fdkanfang.web.backend;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fdkanfang.common.constant.ConstantFilePath;
import com.fdkanfang.common.constant.MsgCode;
import com.fdkanfang.common.constant.TypeCode;
import com.fdkanfang.common.enums.ImageResolutionRate;
import com.fdkanfang.common.enums.ResultCodeEnum;
import com.fdkanfang.common.exception.BaseRuntimeException;
import com.fdkanfang.common.exception.CommonBaseException;
import com.fdkanfang.common.model.PageDto;
import com.fdkanfang.common.util.*;
import com.fdkanfang.domain.backend.*;
import com.fdkanfang.domain.dto.*;
import com.fdkanfang.domain.response.HouseResponse;
import com.fdkanfang.domain.response.UserResponse;
import com.fdkanfang.service.backend.*;
import com.fdkanfang.web.backend.utils.UserUtils;
import com.fdkanfang.web.mq.config.RabbitConfig;
import com.fdkanfang.web.shiro.JWTUtil;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.*;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Condition;

import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;



/**
 * Created by owen on 2020/2/18 0018 12:17
 */
@Api(tags = "房源管理")
@RestController
@RequestMapping("manage/house")
@Transactional
@Log4j2
public class HouseController extends BaseController {

    // 服务器文件保存位置
    @Value("${output.file.path}")
    private String OUTPATH;

    @Value("${server.domain}")
    private String domain;

    @Autowired
    private HouseService2 houseService2;

    @Autowired
    private ImageService2 imageService2;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ISceneProService sceneProService;

    @Autowired
    private ISceneProEditService sceneProEditService;

    @Autowired
    private RoleService2 roleService;

    @Autowired
    private UserUtils userUtils;




    @ApiOperation("房源列表")
    @PostMapping("list")
    public R list(@RequestBody PageDto param){

        String token = getToken();
        // 获取用户角色
        List<String> userRoles = userUtils.getRolesByToken(token);
        UserEntity user  = userUtils.getUserByToken(token);
        Long userId = user.getId();

                PageInfo<HouseResponse> page = null;
        if (userRoles.contains("admin")) {
            page =  new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param, null, null));
        }  else if (userRoles.contains("edit")){

            if (userRoles.size() == 2) {
                log.info("有edit、upload权限");
                // 有edit、upload
//                page =  new PageInfo<>(houseService2.findAllBySearchKey(param, userId, userId));
                page =  new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param, null ,userId));

            } else {
                // 只有edit
                log.info("只有edit权限");
                page =  new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param,  userId , null));

            }

        } else {
            page =  new PageInfo<>(houseService2.findAllBySearchKey(param, userId, null));
        }

        return new R(2000, page);
    }


    /**
     * 服务器版本+垂直校验
     *
     * 使用mq队列
     *
     * 上传文件，不能使用json传参，只能用表单
     *
     * 如果图片审核不通过，就直接把这条记录禁用or删除，从新添加一条。
     * 修改只能修改房源信息，不能修改图片
     *
     * 上传的图片必须是以xxx_xxx.jpg 格式命名，xxx_:图片所属的户型
     *
     *
     * 这里要用手写的表单验证验证方式
     *
     * 提前把垂直校验，模型图片地址写入数据库，需要配合状态来判断算法计算是否完成；
     */
    @RequiresRoles(value = {"admin", "edit", "upload"}, logical = Logical.OR)
    @ApiOperation("新增或修改房源信息 + 垂直校验")
    @PostMapping(value = "save", consumes = {"multipart/form-data"})
    @Transactional(rollbackFor = Exception.class)
    public R save(HouseDto param){

        if(StringUtils.isBlank(param.getDistrictName())){
            log.error("小区名称不能为空");
            return new R(MsgCode.e_COMMON_3001, "小区名称不能为空");
        }
        if(null == param.getFloor() || !StringUtils.isNoneBlank(param.getUnitType() , param.getArea() , param.getOrientation())){
            return new R(MsgCode.e_COMMON_3001, "楼层/户型/面积/朝向不能为空");
        }

        // 处理上传图片
        MultipartFile[] files = param.getFiles();
        if (files == null || files.length <= 0) {
            log.info("文件为空");
            return new R(MsgCode.e_COMMON_3100, MsgCode.msg_COMMON_3100);
        }
        boolean isNewAdd = false;
        HouseEntity house = null;
        if (param.getId() == null) {
            isNewAdd = true;
        }
        house = updateOrInsertHouse(param);
        // 只有新增是才保存图片，修改时另外处理
        if (isNewAdd) {
            //场景码
            String sceneCode = house.getSceneCode();
            boolean needSendMqMsg = false;
            String directoryName = OUTPATH + sceneCode + File.separator + "input_img"+ File.separator;
            FileUtil.mkdir(directoryName);
            HashMap<String, String> ossVerticalImageHighMap = new HashMap<>();
            HashMap<String, String> ossVerticalImageLowMap = new HashMap<>();
            String imageHighPath = null;
            String imageLowPath = null;
            ImageResolutionRate maxResolutionRate = null;
            for (MultipartFile file : files) {
                String filename = file.getOriginalFilename();
                filename = checkAndChangeFileName(filename);
                imageHighPath = OUTPATH + sceneCode + "/output_img/" + filename;
                imageLowPath = OUTPATH + sceneCode + "/output_img_low/" + filename;
                // 提前把算法的图片路径存到数据库，但不代表算法运行成功，最后好是要看house的状态；
                String ossVerticalHighPath = ConstantFilePath.OSS_IMAGE_PATH+ sceneCode+"/pan/high/"+ filename;
                String ossVerticalLowPath = ConstantFilePath.OSS_IMAGE_PATH+ sceneCode+"/pan/low/"+ filename;
                // 封装垂直校验后的图片到信息到oss
                ossVerticalImageHighMap.put(imageHighPath, ossVerticalHighPath);
                ossVerticalImageLowMap.put(imageLowPath, ossVerticalLowPath);
                try {
                    ImageResolutionRate tmpResolutionRate = addAndGetResolutionRate(file , directoryName , ossVerticalHighPath , house.getId());
                    maxResolutionRate = tmpResolutionRate;
                    needSendMqMsg = true;
                } catch (IOException e) {
                    needSendMqMsg = false;
                    log.error("保存照片到本地和持久化image对象出现异常:{}" , e);
                }
            }
            insertScene(maxResolutionRate , house);
            if (needSendMqMsg) {
                HashMap<Object, Object> mqMap = new HashMap<>();
                mqMap.put("ossImageHigh", ossVerticalImageHighMap);
                mqMap.put("ossImageLow", ossVerticalImageLowMap);
                mqMap.put("id", house.getId());
                mqMap.put("basePath", OUTPATH);

                mqMap.put("dataDescribe", "");
                log.info("houseId: {}", house.getId());
                //发消息到mq
                rabbitTemplate.convertAndSend(RabbitConfig.VERTICAL_EXCHANGE, RabbitConfig.VERTICAL_QUEUE_ROUTING, mqMap);
            }
        }
        return new R(MsgCode.SUCCESS_CODE, house);
    }
    @Transactional(rollbackFor = Exception.class)
    public void insertScene(ImageResolutionRate maxResolutionRate , HouseEntity house){
        SceneProEntity sceneProEntity = new SceneProEntity();
        SceneProEditEntity sceneProEditEntity = new SceneProEditEntity();
        if(ImageResolutionRate.TWO_K.equals(maxResolutionRate)){
            //2k
            sceneProEntity.setSceneScheme(11);
        }else{
            //4k
            sceneProEntity.setSceneScheme(10);
        }
        sceneProEntity.setNum(house.getSceneCode());
        //TODO:不知道为何数据库设置的默认不生效
        sceneProEditEntity.setM2dVisi(1);
        sceneProEditEntity.setM3dVisi(1);
        sceneProEditEntity.setPanoVisi(1);
        sceneProEditEntity.setMapVisi(1);
        int insertOne = sceneProService.save(sceneProEntity);
        if(insertOne != 1){
            throw  new CommonBaseException(ResultCodeEnum.D101, "新增scenePro记录失败");
        }
        sceneProEditEntity.setProId(sceneProEntity.getId());
        int insertTwo = sceneProEditService.save(sceneProEditEntity);
        if(insertTwo != 1){
            throw  new CommonBaseException(ResultCodeEnum.D101, "新增sceneProEdit记录失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public ImageResolutionRate addAndGetResolutionRate(MultipartFile file , String directoryName ,
                                                        String ossVerticalHighPath , Long houseId) throws IOException {
        if(null == file || null == houseId){
            log.error("房源id或者文件为空，无法生成image记录");
            return null;
        }
        String filename = file.getOriginalFilename();
        filename = checkAndChangeFileName(filename);

        // 获取图片房间类型
        String imageType = StringUtils.substringBefore(filename, "_");

        // 本地图片保存位置: /root/data/kanfang/场景码/input_img/xxxx.jpg
        String fileFullPath = directoryName + filename;
        ImageEntity image = new ImageEntity();
        image.setVerticalPath(ossVerticalHighPath);
        image.setFileName(filename);
        // 这个参数给前端用，只要有文件名就可以了
        image.setPath(fileFullPath);
        image.setLocalPath(fileFullPath);

        image.setHouseId(houseId);
        // 默认所有图片都是一楼
        image.setFloor(1);
        image.setType(imageType);
        //将图片保存到本地指定目录filePath eg: /root/data/kanfang/d_9iRDUgn3l/input_img/xxx.jpg
        int  resolutionRate = FileUtils.downloanAndGetResolutionRate(file.getInputStream(), fileFullPath , true);
        //照片分辨率
        ImageResolutionRate maxResolutionRate = ImageResolutionRate.getResolutionRateByRate(resolutionRate);
        log.info("照片{}的像素为:{}" , fileFullPath , resolutionRate);
        image.setResolutionRate(null != maxResolutionRate ? maxResolutionRate.name() : "TWO_K");
        int insert = imageService2.save(image);
        if(insert != 1){
            throw  new CommonBaseException(ResultCodeEnum.D101, "新增image记录失败");
        }
        return maxResolutionRate;
    }

    private String checkAndChangeFileName(String filename){

        if(StringUtils.isBlank(filename)){
            throw new CommonBaseException(ResultCodeEnum.D100 , "文件名不能为空");
        }
        if(filename.contains(".JPG")){
            int index = filename.lastIndexOf(".");
            String fileNameWithoutPostfix = filename.substring(0 , index);
            filename = fileNameWithoutPostfix + ".jpg";
            log.info("照片的格式写成了大写，需要转成小写:{}" , filename);
        }
        // 检查一下，生成模型的照片名称不能有"-"，否则生成模型会出现问题
        if (filename.contains("-")) {
            log.error("filename: {}", filename);
            throw new BaseRuntimeException(MsgCode.e_COMMON_3003, "图片命名不符合要求，不能包含符号-，请使用_");
        }
        if (RegexpUtils.isContainChinese(filename)) {
            log.error("图片名称不允许中文字符: {}", filename);
            throw new BaseRuntimeException(MsgCode.e_COMMON_3003, "图片名称不允许中文字符");
        }
        return filename;
    }

    @Transactional(rollbackFor = Exception.class)
    public HouseEntity updateOrInsertHouse(HouseDto param){
        if(null == param){
            return null;
        }
        HouseEntity house = null;
        if (param.getId() == null) {
            house = new HouseEntity();
            UserEntity user  = userUtils.getUserByToken(getToken());
            house.setUserId(user.getId());
            param.setId(null);
            BeanUtils.copyProperties(param, house);
            Integer byMaxNum = houseService2.findByMaxNum();
            // 用于第一条数据
            byMaxNum = (byMaxNum == null)? 10000:byMaxNum;
            String sceneCode = getSceneCode();
            house.setNum(byMaxNum + 1);
            house.setSceneCode(sceneCode);
            house.setWebSite(domain+"?m="+sceneCode);
            house.setFilePath(OUTPATH + sceneCode);
            houseService2.save(house);
        } else {
            house = houseService2.findById(param.getId());
            if (house == null) {
                log.error("房源不存在： {}", param.getId());
                 throw new CommonBaseException(ResultCodeEnum.D101 , "房源不存在");
            }
            BeanUtils.copyProperties(param, house);
            house.setUpdateTime(new Date());
            houseService2.update(house);
        }
        return house;
    }




    @ApiOperation("预审")
    @ResponseBody
    @PostMapping(value = "/auditHouse")
    @Transactional(rollbackFor =  Exception.class)
    public Result auditHouse(@RequestBody  @ApiParam(name = "用户登录注册实体", value = "传入json格式", required = true) HouseAuditDto houseAuditDto) {
        if(StringUtils.isBlank(houseAuditDto.getDesc()) || null == houseAuditDto.getHouseId() || null == houseAuditDto.getResult()){
            throw  new CommonBaseException(ResultCodeEnum.D3001);
        }
        HouseEntity houseEntity = houseService2.findById(houseAuditDto.getHouseId());
        if(null == houseEntity){
            throw  new CommonBaseException(ResultCodeEnum.D101  , "房源不存在");
        }
        if(houseAuditDto.getResult().compareTo(1) != 0 && houseAuditDto.getResult().compareTo(0) != 0){
            throw  new CommonBaseException(ResultCodeEnum.D101  , "审批结果格式不正确");
        }
        houseEntity.setAuditResult(houseAuditDto.getResult());
        houseEntity.setAuditDesc(houseAuditDto.getDesc());
        houseEntity.setUpdateTime(new Date());
        int update = houseService2.update(houseEntity);
        if(update != 1){
            throw  new CommonBaseException(ResultCodeEnum.D101  , "更新房源预审信息失败");
        }
        return Result.success();
    }

    @ApiOperation("标记不能编辑")
    @ResponseBody
    @PostMapping(value = "/markFail")
    public Result markCannotEditHouse(@RequestBody  @ApiParam(name = "用户登录注册实体", value = "传入json格式", required = true) HouseAuditDto houseAuditDto) {
        if(StringUtils.isBlank(houseAuditDto.getDesc()) || null == houseAuditDto.getHouseId()){
            throw  new CommonBaseException(ResultCodeEnum.D3001);
        }
        HouseEntity houseEntity = houseService2.findById(houseAuditDto.getHouseId());
        if(null == houseEntity){
            throw  new CommonBaseException(ResultCodeEnum.D101  , "房源不存在");
        }
        houseEntity.setCanNotEdit(0);
        houseEntity.setCanNotEditDesc(houseAuditDto.getDesc());
        houseEntity.setUpdateTime(new Date());
        int update = houseService2.update(houseEntity);
        if(update != 1){
            throw  new CommonBaseException(ResultCodeEnum.D101  , "更新房源无法制作信息失败");
        }
        return Result.success();
    }

    /**
     *
     * @param houseId
     * @param floor 可选参数
     */
    @ApiOperation("查询房源信息")
    @GetMapping("detail")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "houseId", value = "房源id", required = true),
            @ApiImplicitParam(name = "floor", value = "楼层", required = false)
    })
    public R detail(Long houseId, Integer floor){
        HouseEntity house = houseService2.findById(houseId);
        List<ImageEntity> images = imageService2.findByHouseIdAndFloor(houseId, floor);
        if(null != house){
            house.setImages(images);
            return new R(MsgCode.SUCCESS_CODE, house);
        }else{
            return new R(MsgCode.ERROR_CODE, "房源不存在");
        }
    }



    @RequiresRoles(value = {"admin", "edit", "upload"}, logical = Logical.OR)
    @ApiOperation("删除房源(软删除)")
    @GetMapping("removes/{ids}")
    public R removes(@PathVariable String ids){

        List<String> userRoles = userUtils.getRolesByToken(getToken());
        UserEntity user  = userUtils.getUserByToken(getToken());
        Long loginUserId = user.getId();


        String roleKey = null;
        // 只有一个权限时
        if (userRoles.size() == 1) {
            roleKey = (String)userRoles.get(0);
        }

        String[] split = ids.split(",");
        for (String s : split) {
            HouseEntity houseEntity = houseService2.findById(Long.valueOf(s));
            if (houseEntity == null) {
                log.error("房源id有误，没有存在的房源");
                return new R(MsgCode.e_COMMON_3002,"没有存在的房源");
            }



            if ("upload".equals(roleKey)) {
                if(null != houseEntity.getAuditResult() && houseEntity.getAuditResult().compareTo(1) == 0){
                    log.error("只有upload, 房源id!=0,审批通过的房源不能删除");
                    return new R(MsgCode.e_COMMON_3002,"审批通过的房源不能删除");
                }
            }

            if ("edit".equals(roleKey)) {
                log.error("只有edit,没有权限删除房源");
                return new R(MsgCode.e_COMMON_3002,"没有权限删除房源");
            }

            if (!loginUserId.equals(houseEntity.getUserId()) && !userRoles.contains("admin")) {
                log.error("userId: {}, loginUserId: {}", houseEntity.getUserId(), loginUserId);
                log.error("用户不相等时, edit,upload不能删除他人房源");
                return new R(MsgCode.e_COMMON_3002,"没有权限删除房源");
            }

            houseEntity.setRecStatus("I");
            houseEntity.setUpdateTime(new Date());
            houseService2.update(houseEntity);
        }

        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }


    /**
     * 更新sceneJson（写到另一个字段）, 保留原始sceneJson数据
     *
     */
    @RequiresRoles(value = {"admin", "edit"}, logical = Logical.OR)
    @ApiOperation("更新sceneJson")
    @PostMapping("update/sceneJson")
    public R updateSceneJson(@Valid @RequestBody SceneJsonDto param){

        HouseEntity house = houseService2.findById(param.getId());
        if (house == null) {
            log.error("房源id不存在");
            return new R(MsgCode.e_COMMON_3001, "房源id不存在");
        }

        house.setNewSceneJson(param.getSceneJson());
        house.setUpdateTime(new Date());

        houseService2.update(house);

        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }






    @ApiOperation("获取楼层户型图")
    @GetMapping("image/find/floor/{houseId}/{floor}")
    public R findImageByFloor(@PathVariable Long houseId, @PathVariable Integer floor){
        List<ImageEntity> images = imageService2.findByHouseIdAndFloor(houseId, floor);
        return new R(MsgCode.SUCCESS_CODE, images);
    }


    /**
     * 只有管理员才能分配制作人
     * 制作人是edit角色
     */
    @RequiresRoles(value = {"admin"}, logical = Logical.OR)
    @ApiOperation("获取制作人")
    @GetMapping("getHandler")
    public R getHandler(){
        // 根据edit权限查询用户
        List<UserResponse> usre = roleService.findUserByRoleKey("edit");
        return new R(MsgCode.SUCCESS_CODE, usre);
    }


    @RequiresRoles(value = {"admin"}, logical = Logical.OR)
    @ApiOperation("分配制作人")
    @GetMapping("setHandler/{houseId}/{userId}")
    public R setHandler(@PathVariable Long houseId, @PathVariable Long userId){

        // 根据edit权限查询用户
        HouseEntity houseEntity = houseService2.findById(houseId);
        if (houseEntity == null) {
            log.error("房源不存在: {}", houseId);
            return new R(MsgCode.e_COMMON_3001, "房源不存在");
        }
        houseEntity.setHandler(userId);
        houseEntity.setUpdateTime(new Date());

        houseService2.update(houseEntity);
        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }


    @ApiOperation("查询房源图片")
    @GetMapping("image/detail/{id}")
    public R imageDetail(@PathVariable Long id){
        return new R(MsgCode.SUCCESS_CODE, imageService2.findById(id));
    }

    @RequiresRoles(value = {"admin", "edit"}, logical = Logical.OR)
    @ApiOperation("编辑图片信息")
    @PostMapping("image/edit")
    public R imageEdit(@RequestBody ImageDto param){
        ImageEntity image = imageService2.findById(param.getId());
        if (image == null){
            log.error("图片id不存在： {}" , param.getId());
            throw new BaseRuntimeException(MsgCode.e_COMMON_3002, MsgCode.msg_COMMON_3002);
        }
        BeanUtils.copyProperties(param, image);
        image.setUpdateTime(new Date());

        imageService2.update(image);
        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }


    @RequiresRoles(value = {"admin", "edit"}, logical = Logical.OR)
    @ApiOperation("批量编辑图片信息")
    @PostMapping("image/edit/all")
    public R imageEdit(@RequestBody Map<Long, String> param){

        for (Map.Entry<Long, String> a : param.entrySet()) {
            ImageEntity image = imageService2.findById(a.getKey());
            image.setUpdateTime(new Date());
            image.setIssue(a.getValue());
            imageService2.update(image);

        }

        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }



    /**
     * 陈世超的算法
     * 调用算法计算场景,生产全景图
     *
     * 图片是用垂直校验后的图片
     *
     * Content传到后台会生成两个文件：floorplan.json、vision.txt
     */
    @RequiresRoles(value = {"admin", "edit"}, logical = Logical.OR)
    @ApiOperation("生成模型")
    @PostMapping("rsa/pano")
    @Transactional(rollbackFor = Exception.class)
    public R rsaPano(@Valid @RequestBody PanoDto param) throws Exception {
        log.info("run rsaPano");

        if (param == null) {
            log.error("参数为空");
            return new R(50001, "error");
        }
        HouseEntity house = houseService2.findById(param.getHouseId());
        if (house == null) {
            log.error("房源不存在： {}", param.getHouseId());
            return new R(MsgCode.e_COMMON_3002, MsgCode.msg_COMMON_3002);
        }

        String sceneCode = house.getSceneCode();

        boolean flagQ = false;
        // data/kanfang/10001/pano
        String savePath = OUTPATH + sceneCode + "/" + TypeCode.SCENE_PANO;
        // 检查场景码对应的pano文件夹是否存在，存在则删除里面的内容（用户从新编辑场景）
        if (FileUtil.isDirectory(savePath)) {
            FileUtil.del(savePath);
            log.info("删除旧目录重新计算： {}", sceneCode);
        }

        log.warn("savePath: {}", savePath);
        String sourcePath = savePath + "/extras/";
        try {

            FileUtils.createDir(sourcePath);
/*
          /***
                 * 以下字段为给算法部传递的参数（data.json），用于生成模型和
                 * 照片，提供前端使用,完整的参数如下：
                 * {
                 * 	"split_type": "SPLIT_V5",
                 * 	"skybox_type": "SKYBOX_V5",
                 * 	"extras": {
                 * 		"has_vision_txt": true,
                 * 		"has_floorplan_json": true,
                 * 		"has_source_images": true
                 *        }
                 * }
                 * */
            String content = "";
            //生成data.json供算法部使用
            JSONObject dataJson = new JSONObject();
            dataJson.put("split_type", "SPLIT_V5");
            String imageResolution = checkImageResolutionRate(house);
            if(ImageResolutionRate.TWO_K.name().equals(imageResolution)){
                //2 K 照片
                dataJson.put("skybox_type", "SKYBOX_V7");
            }else{
                //4 k照片
                dataJson.put("skybox_type", "SKYBOX_V6");
            }
            dataJson.put("extras", null);
            JSONObject extrasJson = new JSONObject();
            extrasJson.put("has_vision_txt" , true);
            extrasJson.put("has_floorplan_json" , true);
            extrasJson.put("has_source_images" , true);
            dataJson.put("extras" , extrasJson);
            FileUtils.fileWriter(dataJson.toJSONString(), savePath + "/data.json");
            log.warn("dataJson的生成路径: {}", savePath + "/data.json");

            // 解析json
            JSONObject original = JSON.parseObject(param.getContent());

            // 获取modelData, cameraData
            String floorPlan = original.getString("floorplan");
            String vision = original.getString("vision");

            if (floorPlan == null) {
                log.error("floorPlan不能为空");
                return new R(50002, "floorPlan不能为空");
            }

            if (vision == null) {
                log.error("vision不能为空");
                return new R(50002, "vision不能为空");
            }

            // json写入服务器
            FileUtils.fileWriter(floorPlan, sourcePath + "floorplan.json");
            FileUtils.fileWriter(vision, sourcePath + "vision.txt");



            log.info("floorplan.json生成完成");
            log.info("vision.txt生成完成");

            // 复制垂直校验图片到指定目录
            String verticalImagePath = OUTPATH + sceneCode+"/output_img";
            String panoImagePath = sourcePath + "images/";

            // srcPath: /data/kanfang/10002/output_img
            log.info("srcPath: {}", verticalImagePath);

            // target: /data/kanfang/10002/pano/extras/images/
            log.info("target: {}", panoImagePath);

            FileUtil.copyFilesFromDir(new File(verticalImagePath), new File(panoImagePath), true);

            flagQ = true;

        } catch (Exception e) {
            e.printStackTrace();
            log.error("出错了……");
            return new R(50002, e.getMessage());
        }

        if (flagQ) {
            HashMap<Object, Object> mqMap = new HashMap<>();
            mqMap.put("id", house.getId());
            mqMap.put("basePath", savePath);

            // 上传floorplan.json到oss, 并命名为floor.json
            HashMap<String, String> uploadJson = new HashMap<>();

            // osspath : images/images+sceneCode/floor.json
            uploadJson.put(sourcePath + "floorplan.json", ConstantFilePath.OSS_FLOOR_PATH+sceneCode+"/floor.json");
            AliyunOssUtil.uploadMulFiles(uploadJson);

            // savePath:/data/kanfang/房源编号/
            // basePath: /data/kanfang/10002/pano
            log.info("basePath: {}", savePath);
            log.info("houseId: {}", house.getId());

            //发消息到mq
            rabbitTemplate.convertAndSend(RabbitConfig.PANO_EXCHANGE, RabbitConfig.PANO_QUEUE_ROUTING, mqMap);

            // 修改房源状态, 3:模型计算中
            house.setStatus(3);
            house.setUpdateTime(new Date());
            houseService2.update(house);


            // 每点击生成模型一次，就修改SceneProEditEntity的部分值
            SceneProEntity sceneProEntity = sceneProService.findBySceneNum(house.getSceneCode());
            if (sceneProEntity == null) {
                log.error("sceneProEntity对象不存在：{}", house.getSceneCode());
                return new R(MsgCode.ERROR_CODE, "sceneProEntity对象不存在");
            }
            SceneProEditEntity proEditEntity = sceneProEditService.findByProId(sceneProEntity.getId());
            proEditEntity.setVersion(proEditEntity.getVersion() + 1);
            proEditEntity.setFloorEditVer(proEditEntity.getFloorEditVer() + 1);
            proEditEntity.setFloorPublishVer(proEditEntity.getFloorPublishVer() + 1);
            proEditEntity.setUpdateTime(new Date());

            sceneProEditService.update(proEditEntity);
            log.info("更新SceneProEditEntity数据完成");

            log.info("入队成功");
        }

        return new R(MsgCode.SUCCESS_CODE, house);
    }

    private String checkImageResolutionRate(HouseEntity houseEntity){
        if(null == houseEntity || null == houseEntity.getId()){
            return null;
        }
        List<ImageEntity> imageEntities = imageService2.findByHouseId(houseEntity.getId());
        if(CollectionUtils.isEmpty(imageEntities)){
            log.error("房源[{}]下面无照片，默认返回2k的分辨率");
            return ImageResolutionRate.TWO_K.name();
        }
        int sort = 0;
        ImageResolutionRate maxResolution = null;
        for (ImageEntity imageEntity : imageEntities){
            if(StringUtils.isBlank(imageEntity.getResolutionRate())){
                log.warn("房源[{}]的照片[{}]没有设置照片分辨率，跳过" , houseEntity.getId() , imageEntity.getId());
                break;
            }
            ImageResolutionRate curResolution = ImageResolutionRate.getResolutionByName(imageEntity.getResolutionRate());
            if(null != curResolution){
                if(curResolution.getOrder() > sort){
                    sort = curResolution.getOrder();
                    maxResolution = curResolution;
                }
            }
        }
        log.info("房源[{}]的照片最大的分辨率为:{}" , houseEntity.getId() , null != maxResolution ? maxResolution.name() :"空值");
        return null != maxResolution ? maxResolution.name() : ImageResolutionRate.TWO_K.name();
    }


    /***
     * 获取唯一场景码
     */
    private String getSceneCode(){
        String randowString = null;
        Condition condition = new Condition(HouseEntity.class);

        List<HouseEntity> all = null;

        boolean flag = true;
        while (flag) {
            randowString = RandomUtils.randowString(9);
            condition.and().andEqualTo("sceneCode", randowString);
            all = houseService2.findAll(condition);
            log.info(all.size());
            flag = all.size() > 0;
        }
        log.info("code: {}", randowString);
        return "d_" + randowString;
    }




}
