package com.fdkankan.ucenter.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fdkankan.common.constant.ErrorCode;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.util.FileUtils;
import com.fdkankan.ucenter.common.constants.ConstantFilePath;
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.ucenter.common.ResultData;
import com.fdkankan.ucenter.entity.SceneEditInfo;
import com.fdkankan.ucenter.mapper.ISceneEditInfoMapper;
import com.fdkankan.ucenter.service.ISceneEditInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 
 * @since 2022-07-12
 */
@Service
public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper, SceneEditInfo> implements ISceneEditInfoService {

    @Autowired
    RedisUtil redisUtil;
    @Autowired
    private RedisLockUtil redisLockUtil;


    @Override
    public SceneEditInfo getByScenePlusId(Long plusId) {
        return this.getOne(new LambdaQueryWrapper<SceneEditInfo>()
                .eq(SceneEditInfo::getScenePlusId, plusId));
    }

    @Override
    public List<JSONObject> getMosaicList(String num) throws Exception {
        //如果redis数据丢失，从本地文件中同步马赛克数据到redis
        this.syncMosaicFromFileToRedis(num);

        String key = String.format(RedisKey.SCENE_MOSAIC_DATA, num);
        Map<String, String> map = redisUtil.hmget(key);
        if(CollUtil.isEmpty(map)){
            ResultData.ok(new String[0]);
        }
        return map.values().stream()
                .map(mosaic-> JSON.parseObject(mosaic))
                .collect(Collectors.toList());
    }


    /**
     * <p>
     保证马赛克数据安全性，当redis宕机导致热点数据丢失时，可以从文件中读取，恢复到redis
     **/
    private void syncMosaicFromFileToRedis(String num) throws Exception{

        String key = String.format(RedisKey.SCENE_MOSAIC_DATA, num);
        boolean exist = redisUtil.hasKey(key);
        if(exist){
            return;
        }
        String lockKey = String.format(RedisLockKey.LOCK_MOSAIC_DATA_SYNC, num);
        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
        if(!lock){
            throw new BusinessException(ErrorCode.SYSTEM_BUSY);
        }
        try{
            exist = redisUtil.hasKey(key);
            if(exist){
                return;
            }
            String filePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
            String mosaicData = FileUtils.readFile(filePath + "mosaic.json");
            if(StrUtil.isEmpty(mosaicData)){
                return;
            }
            JSONArray jsonArray = JSON.parseArray(mosaicData);
            if(CollUtil.isEmpty(jsonArray)){
                return;
            }
            Map<String, String> map = new HashMap<>();
            for (Object o : jsonArray) {
                JSONObject jo = (JSONObject)o;
                map.put(jo.getString("panoId"), jo.toJSONString());
            }
            redisUtil.hmset(key, map);
        }finally {
            redisLockUtil.unlockLua(lockKey);
        }
    }

    /**
     * <p>
     保证马赛克数据安全性，当redis宕机导致热点数据丢失时，可以从文件中读取，恢复到redis
     **/
    private void writeMosaic(String num) throws Exception{

        String mosaicPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "mosaic.json";

        String key = String.format(RedisKey.SCENE_MOSAIC_DATA, num);
        Map<String, String> mosaicMap = redisUtil.hmget(key);
        if(CollUtil.isEmpty(mosaicMap)){
            FileUtils.deleteFile(mosaicPath);
            return;
        }
        List<String> mosaicList = Lists.newArrayList(mosaicMap.values());
        JSONArray jsonArr = new JSONArray();
        mosaicList.stream().forEach(mosaic->{
            jsonArr.add(JSONObject.parseObject(mosaic));
        });


        String lockKey = String.format(RedisLockKey.LOCK_MOSAIC_JSON, num);
        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
        if(!lock){
            return;
        }
        try{
            FileUtils.writeFile(mosaicPath, jsonArr.toJSONString());
        }finally {
            redisLockUtil.unlockLua(lockKey);
        }
    }
}
