package com.fdkankan.scene.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fdkankan.common.constant.ConstantFilePath;
import com.fdkankan.common.constant.ErrorCode;
import com.fdkankan.common.response.ResultData;
import com.fdkankan.fyun.oss.UploadToOssUtil;
import com.fdkankan.rabbitmq.util.RabbitMqProducer;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.constant.RedisLockKey;
import com.fdkankan.redis.util.RedisLockUtil;
import com.fdkankan.redis.util.RedisUtil;
import com.fdkankan.scene.bean.SceneUpgradeProgressBean;
import com.fdkankan.scene.entity.ScenePlus;
import com.fdkankan.scene.entity.ScenePlusExt;
import com.fdkankan.scene.entity.SceneProEdit;
import com.fdkankan.scene.entity.SceneProEditExt;
import com.fdkankan.scene.entity.SceneProEditV3;
import com.fdkankan.scene.entity.SceneProExt;
import com.fdkankan.scene.entity.SceneProV3;
import com.fdkankan.scene.entity.SceneRepairLog;
import com.fdkankan.scene.mapper.ISceneUpgradeMapper;
import com.fdkankan.scene.service.IScenePlusExtService;
import com.fdkankan.scene.service.IScenePlusService;
import com.fdkankan.scene.service.ISceneProEditExtService;
import com.fdkankan.scene.service.ISceneProEditService;
import com.fdkankan.scene.service.ISceneProEditV3Service;
import com.fdkankan.scene.service.ISceneProExtService;
import com.fdkankan.scene.service.ISceneProService;
import com.fdkankan.scene.service.ISceneProV3Service;
import com.fdkankan.scene.service.ISceneRepairLogService;
import com.fdkankan.scene.service.ISceneUpgradeToV4Service;
import com.fdkankan.scene.vo.SceneInfoVO;
import com.fdkankan.scene.vo.UpgradeToV4ParamVO;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * <p>
 * TODO
 * </p>
 *
 * @author dengsixing
 * @since 2022/4/21
 **/
@Slf4j
@Service
public class SceneUpgradeToV4Service implements ISceneUpgradeToV4Service {

    @Value("${queue.scene.upgrade-to-v4}")
    private String upgradeToV4;
    @Value("${oss.bucket:4dkankan}")
    private String bucket;

    @Autowired
    private ISceneProV3Service sceneProV3Service;
    @Autowired
    private ISceneProEditV3Service sceneProEditV3Service;
    @Autowired
    private ISceneUpgradeMapper sceneUpgradeMapper;
    @Autowired
    private RedisLockUtil redisLockUtil;
    @Autowired
    private ISceneRepairLogService sceneRepairLogService;
    @Autowired
    private RabbitMqProducer rabbitMqProducer;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ISceneProService sceneProService;
    @Autowired
    private ISceneProExtService sceneProExtService;
    @Autowired
    private IScenePlusService scenePlusService;
    @Autowired
    private IScenePlusExtService scenePlusExtService;
    @Autowired
    private ISceneProEditService sceneProEditService;
    @Autowired
    private ISceneProEditExtService sceneProEditExtService;
    @Autowired
    private UploadToOssUtil uploadToOssUtil;

    @Override
    public ResultData upgradeToV4(UpgradeToV4ParamVO param) {

        SceneProV3 sceneProV3 = JSON.parseObject(param.getScenePro(), SceneProV3.class);
        SceneProEditV3 sceneProEditV3 = JSON.parseObject(param.getSceneProEdit(), SceneProEditV3.class);

        //加锁
        String lockKey = String.format(RedisLockKey.LOCK_SCENE_UPGRADE_V4, sceneProV3.getNum());
        boolean lock = redisLockUtil.lock(lockKey,RedisKey.EXPIRE_TIME_2_HOUR);
        if(!lock){
            return ResultData.error(ErrorCode.FAILURE_CODE_7019);
        }

        try {
            //查询升级日志，如果已经升级成功，不允许重复升级
            SceneRepairLog sceneRepairLog = sceneRepairLogService.getOne(
                new LambdaQueryWrapper<SceneRepairLog>()
                    .eq(SceneRepairLog::getNum, sceneProV3.getNum()));
            if(Objects.nonNull(sceneRepairLog)){
                if(sceneRepairLog.getState() == 0){
                    redisLockUtil.unlockLua(lockKey);
                    return ResultData.error(ErrorCode.FAILURE_CODE_7019);
                }
                if(sceneRepairLog.getState() == 1){
                    redisLockUtil.unlockLua(lockKey);
                    return ResultData.error(ErrorCode.FAILURE_CODE_7020);
                }
            }

            //写入sceneProV3
            sceneProV3Service.saveOrUpdate(sceneProV3);

            //写入sceneProEditV3
            sceneProEditV3Service.saveOrUpdate(sceneProEditV3);

            //写入sceneProEdit、写入sceneProEditExt
            sceneUpgradeMapper.deleteSceneProEdit(sceneProEditV3.getId());
            sceneUpgradeMapper.transferSceneProEdit(sceneProEditV3.getId());
            sceneUpgradeMapper.deleteSceneProEditExt(sceneProEditV3.getId());
            sceneUpgradeMapper.transferSceneProEditExt(sceneProEditV3.getId());

            //同步到scenePro、sceneProExt
            sceneUpgradeMapper.deleteScenePro(sceneProV3.getId());
            sceneUpgradeMapper.transferScenePro(sceneProV3.getId());
            sceneUpgradeMapper.deleteSceneProExt(sceneProV3.getId());
            sceneUpgradeMapper.transferSceneProExt(sceneProV3.getId());

            //同步到scenePlus、scenePlus
            sceneUpgradeMapper.deleteScenePlus(sceneProV3.getId());
            sceneUpgradeMapper.transferScenePlus(sceneProV3.getId());
            sceneUpgradeMapper.deleteScenePlusExt(sceneProV3.getId());
            sceneUpgradeMapper.transferScenePlusExt(sceneProV3.getId());

            //发送mq
            rabbitMqProducer.sendByWorkQueue(upgradeToV4, sceneProV3.getId());

            //写入进度条
            Map<String, Integer> progress = new HashMap<>();
            progress.put("status", 0);
            progress.put("progress", 0);
            redisUtil.set(RedisKey.scene_upgrade_progress_num, JSON.toJSONString(progress));

        }catch (Exception e){
            log.error("场景升级失败", e);
            return ResultData.error(ErrorCode.FAILURE_CODE_7021);
        }

        return ResultData.ok();
    }

    @Override
    public ResultData getUpgradeToV4Progress(String num) {

        String key = String.format(RedisKey.scene_upgrade_progress_num, num);
        String progress = redisUtil.get(key);
        SceneUpgradeProgressBean progressBean = null;
        if(StrUtil.isNotEmpty(progress)){
            progressBean = JSON.parseObject(progress, SceneUpgradeProgressBean.class);
        }else{
            progressBean = SceneUpgradeProgressBean.builder().num(num).status(0).progress(0).build();
        }
        return ResultData.ok(progressBean);
    }

    @Override
    public ResultData getSceneViewInfo(String num) {
        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
        String key = String.format(RedisKey.SCENE_JSON, num);
        String sceneJson = redisUtil.get(key);
        SceneInfoVO sceneInfoVO = null;
        //先查询redis
        if(StrUtil.isNotEmpty(sceneJson)) {
            sceneInfoVO = JSON.parseObject(sceneJson, SceneInfoVO.class);
            sceneInfoVO.setScenePassword(null);
            if(Objects.isNull(sceneInfoVO.getFloorPlanAngle())){
                sceneInfoVO.setFloorPlanAngle(0f);
            }
            if(Objects.isNull(sceneInfoVO.getFloorPlanCompass())){
                sceneInfoVO.setFloorPlanCompass(0f);
            }
            return ResultData.ok(sceneInfoVO);
        }

        //如果redis没找到，从scene.json中获取
        String objectName = String.format(ConstantFilePath.SCENE_VIEW_DATA_DATA_SCENEJSON, num);
        String objectContent = uploadToOssUtil.getObjectContent(bucket, objectName);
        if(StrUtil.isEmpty(objectContent))
            return ResultData.ok();
        sceneInfoVO = JSON.parseObject(objectContent, SceneInfoVO.class);
        sceneInfoVO.setScenePassword(null);
        if(Objects.isNull(sceneInfoVO.getFloorPlanAngle())){
            sceneInfoVO.setFloorPlanAngle(0f);
        }
        if(Objects.isNull(sceneInfoVO.getFloorPlanCompass())){
            sceneInfoVO.setFloorPlanCompass(0f);
        }
        return ResultData.ok(sceneInfoVO);
    }
}
