package com.fdkankan.scene.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fdkankan.common.constant.*;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.response.ResultData;
import com.fdkankan.fyun.oss.UploadToOssUtil;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.util.RedisUtil;
import com.fdkankan.scene.bean.SceneJsonBean;
import com.fdkankan.scene.entity.SceneEditControls;
import com.fdkankan.scene.entity.SceneEditInfo;
import com.fdkankan.scene.entity.ScenePro;
import com.fdkankan.scene.factory.FloorLogoHandlerFactory;
import com.fdkankan.scene.factory.MusicHandlerFactory;
import com.fdkankan.scene.mapper.ISceneEditInfoMapper;
import com.fdkankan.scene.service.ISceneEditControlsService;
import com.fdkankan.scene.service.ISceneEditInfoService;
import com.fdkankan.scene.service.ISceneProService;
import com.fdkankan.scene.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Calendar;
import java.util.Objects;

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

    @Value("${oss.bucket:4dkankan}")
    private String bucket;
    @Autowired
    private ISceneEditControlsService sceneEditControlsService;
    @Autowired
    private ISceneProService sceneProService;
    @Autowired
    private UploadToOssUtil uploadToOssUtil;
    @Autowired
    RedisUtil redisUtil;


    @Override
    public SceneEditInfoVO saveScene(SceneEditInfoParamVO param) {

        ScenePro scenePro = sceneProService.findBySceneNum(param.getNum());
        if(Objects.isNull(scenePro)){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
        }
        SceneEditInfo sceneEditInfoDb = this.getBySceneProId(scenePro.getId());
        SceneEditControls sceneEditControlsDb = null;
        if(Objects.nonNull(sceneEditInfoDb)){
            sceneEditControlsDb = sceneEditControlsService.getBySceneEditId(sceneEditInfoDb.getId());
        }

        SceneEditInfo sceneEditInfo = BeanUtil.copyProperties(param, SceneEditInfo.class);
        sceneEditInfo.setSceneProId(scenePro.getId());
        sceneEditInfo.setCreateTime(Calendar.getInstance().getTime());
        if(Objects.isNull(sceneEditInfoDb)){
            this.save(sceneEditInfo);
        }else{
            sceneEditInfo.setId(sceneEditInfoDb.getId());
            sceneEditInfo.setUpdateTime(Calendar.getInstance().getTime());
            this.updateById(sceneEditInfo);
        }

        if(Objects.nonNull(param.getControls())){
            SceneEditControls sceneEditControls = BeanUtil.copyProperties(param.getControls(), SceneEditControls.class);
            sceneEditControls.setEditInfoId(sceneEditInfo.getId());
            if(Objects.isNull(sceneEditControlsDb)){
                sceneEditControlsService.save(sceneEditControls);
            }else{
                sceneEditControls.setId(sceneEditControlsDb.getId());
                sceneEditControlsService.updateById(sceneEditControls);
            }
        }

        SceneEditInfoVO result = BeanUtil.copyProperties(param, SceneEditInfoVO.class);
        result.setCreateTime(sceneEditInfo.getCreateTime());

        return result;
    }

    @Override
    public SceneEditInfo getBySceneProId(long sceneProId) {
        return this.getOne(new LambdaQueryWrapper<SceneEditInfo>()
                .eq(SceneEditInfo::getTbStatus, TbStatus.VALID.code())
                .eq(SceneEditInfo::getSceneProId, sceneProId));
    }

    @Override
    public ResultData publicScene(SceneEditInfoParamVO param) throws Exception {
        String sceneNum = param.getNum();
        if(StrUtil.isEmpty(sceneNum)){
            throw new BusinessException(ErrorCode.PARAM_REQUIRED);
        }

        //根据场景码查询数据库
        ScenePro scenePro = sceneProService.findBySceneNum(sceneNum);
        SceneEditInfo sceneEditInfo = this.getBySceneProId(scenePro.getId());
        SceneEditControls sceneEditControls = sceneEditControlsService.getBySceneEditId(sceneEditInfo.getId());

        //生成sceneJson
        SceneJsonBean sceneJson = BeanUtil.copyProperties(sceneEditInfo, SceneJsonBean.class);
        SceneEditControlsVO sceneEditControlsVO = BeanUtil.copyProperties(sceneEditControls, SceneEditControlsVO.class);
        sceneJson.setControls(sceneEditControlsVO);
        sceneJson.setNum(sceneNum);

        //上传sceneJson文件
        String sceneJsonPath = String.format(ConstantFilePath.SCENE_VIEW_DATA_DATA_SCENEJSON, sceneNum);
        uploadToOssUtil.upload(JSON.toJSONBytes(sceneJson), sceneJsonPath);

        //删除发布数据中的user目录
        String publicUserPath = String.format(ConstantFilePath.SCENE_VIEW_DATA_USER, sceneNum);
        uploadToOssUtil.deleteFile(publicUserPath);

        //复制编辑数据到发布目录
        String editUserPath = String.format(ConstantFilePath.SCENE_EDIT_DATA_USER, sceneNum);
        uploadToOssUtil.copyFiles(editUserPath,publicUserPath);

        //sceneJson放入缓存
        String key = String.format(RedisKey.SCENE_JSON, sceneNum);
        redisUtil.set(key, JSON.toJSONString(sceneJson));

        return ResultData.ok();
    }

    @Override
    public SceneInfoVO getSceneInfo(SceneInfoParamVO param) {
        SceneInfoReqType sceneInfoReqType = SceneInfoReqType.get(param.getReqType());
        switch (sceneInfoReqType){
            //如果是编辑页面请求，查数据库
            case EDIT:
                return this.getSceneInfo4Edit(param.getNum());
            //如果是查看页面请求，查redis
            case VIEW:
                return this.getSceneInfo4View(param.getNum());
        }
        return null;
    }

    /**
     * <p>
            编辑页面获取场景详情信息
     * </p>
     * @author dengsixing
     * @date 2022/1/21
     * @param num
     * @return com.fdkankan.scene.vo.SceneInfoVO
     **/
    private SceneInfoVO getSceneInfo4Edit(String num){
        ScenePro scenePro = sceneProService.findBySceneNum(num);
        if(Objects.isNull(scenePro)){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
        }
        SceneEditInfo sceneEditInfo = this.getBySceneProId(scenePro.getId());
        SceneEditControls sceneEditControls = sceneEditControlsService.getBySceneEditId(sceneEditInfo.getId());
        SceneInfoVO sceneInfoVO = BeanUtil.copyProperties(sceneEditInfo, SceneInfoVO.class);
        sceneInfoVO.setControls(BeanUtil.copyProperties(sceneEditControls, SceneEditControlsVO.class));
        sceneInfoVO.setNum(num);

        return sceneInfoVO;
    }

    /**
     * <p>
     查看页面获取场景详情信息
     * </p>
     * @author dengsixing
     * @date 2022/1/21
     * @param num
     * @return com.fdkankan.scene.vo.SceneInfoVO
     **/
    private SceneInfoVO getSceneInfo4View(String num){
        String sceneJson = redisUtil.get(String.format(RedisKey.SCENE_JSON, num));
        SceneInfoVO sceneInfoVO = null;
        //先查询redis
        if(StrUtil.isNotEmpty(sceneJson)){
            sceneInfoVO = JSON.parseObject(sceneJson, SceneInfoVO.class);
            return 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 null;
        sceneInfoVO = JSON.parseObject(objectContent, SceneInfoVO.class);

        return sceneInfoVO;
    }

    @Override
    public ResultData saveUpload(SaveUploadParamVO param) {
        FileBizType fileBizType = FileBizType.get(param.getType());
        if(Objects.isNull(fileBizType)){
            throw new BusinessException(ErrorCode.FAILURE_CODE_7003);
        }
        switch (fileBizType){
            case MUSIC:
                return new MusicHandlerFactory().getHandler().save(param.getNum(), param.getFileInfo());
            case FLOOR_LOGO:
                return new FloorLogoHandlerFactory().getHandler().save(param.getNum(), param.getFileInfo());
        }


        return ResultData.ok();
    }

}
