package com.fdkankan.scene.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fdkankan.common.bean.DownLoadProgressBean;
import com.fdkankan.common.bean.DownLoadTaskBean;
import com.fdkankan.common.constant.*;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.response.PageInfo;
import com.fdkankan.common.response.ResultData;
import com.fdkankan.common.user.SSOLoginHelper;
import com.fdkankan.common.user.SSOUser;
import com.fdkankan.common.util.PageInfoUtils;
import com.fdkankan.platform.api.dto.Camera;
import com.fdkankan.platform.api.dto.User;
import com.fdkankan.platform.api.feign.PlatformGoodsClient;
import com.fdkankan.platform.api.feign.PlatformUserClient;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.util.RedisUtil;
import com.fdkankan.scene.api.dto.SceneCntDTO;
import com.fdkankan.scene.api.dto.SceneProDTO;
import com.fdkankan.scene.entity.*;
import com.fdkankan.scene.mapper.ISceneProMapper;
import com.fdkankan.scene.service.*;
import com.fdkankan.scene.util.ParamConvertUtil;
import com.fdkankan.scene.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserSceneServiceImpl implements IUserSceneService {

    @Autowired
    private SSOLoginHelper ssoLoginHelper;
    @Autowired
    private PlatformGoodsClient platformGoodsClient;
    @Autowired
    private PlatformUserClient platformUserClient;
    @Autowired
    private ISceneCooperationService sceneCooperationService;
    @Autowired
    private ISceneService sceneService;
    @Autowired
    private ISceneProService sceneProService;
    @Autowired
    private ISceneProExtService sceneProExtService;
    @Autowired
    private IFolderService folderService;
    @Autowired
    private IFolderSceneService folderSceneService;
    @Autowired
    private ISceneProMapper sceneProMapper;
    @Autowired
    private ISceneEditInfoExtService sceneEditInfoExtService;
    @Autowired
    private IScenePlusService scenePlusService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ISceneEditInfoService sceneEditInfoService;
    @Autowired
    private ISceneDownloadLogService sceneDownloadLogService;
    @Autowired
    private IFdkkLaserService fdkkLaserService;

    @Override
    public Page<SceneVO> getScenes(String token, SceneParamVO param) {
        SSOUser ssoUser = ssoLoginHelper.loginCheck(token);
        if(ssoUser == null){
            throw new BusinessException(ErrorCode.USER_NOT_LOGIN);
        }
        Long userId = ssoUser.getId();
        param.setUserId(userId);
        String cameraId = null;
        String nums = null;
        log.info("搜索条件是："+ param.getSearchKey());
        //type为12表示一键换装的请求，不查询相机数据
        if(StringUtils.isNotEmpty(param.getSearchKey()) && !"11".equals(param.getType())){
            List<Camera> cameraEntityList = platformGoodsClient.getCameraLikeSnCode(param.getSearchKey()).getData();
            cameraId = cameraEntityList.parallelStream().map(entity->"'"+entity.getId()+"'").collect(Collectors.joining(","));

            List<User> userList  = platformUserClient.getUserLikeUserName(param.getSearchKey()).getData();
            List<Long> userIds =  userList.parallelStream().map(User::getId).collect(Collectors.toList());

            if(userIds.size() > 0){
                List<SceneCooperation> cooperationList = sceneCooperationService.getListByUserId(userIds);
                nums = cooperationList.parallelStream().map(entity->"'"+entity.getNum()+"'").collect(Collectors.joining(","));
                param.setNums(nums);
            }
        }
        param.setCameraIds(cameraId);
        Page<SceneProPO> proPOPage = sceneService.findAllScene( param);

        Page<SceneVO> pageInfo = new Page<>(proPOPage.getCurrent(),proPOPage.getSize());
        pageInfo.setTotal(proPOPage.getTotal());
        pageInfo.setRecords(proPOPage.getRecords().stream().map(sceneProPO -> {
            SceneVO sceneVO = new SceneVO();
            BeanUtils.copyProperties(sceneProPO,sceneVO);
            return sceneVO;
        }).collect(Collectors.toList()));

        List<SceneVO> list = pageInfo.getRecords();
        list.parallelStream().forEach(responseScene->{
            if(responseScene.getCameraId() != null){
                Camera cameraEntity = platformGoodsClient.getCameraById(responseScene.getCameraId()).getData();
                if(cameraEntity != null){
                    responseScene.setChildName(cameraEntity.getChildName());
                    responseScene.setSnCode(cameraEntity.getSnCode());
                }
            }

            if(responseScene.getUserId()!=null){
                String username = platformUserClient.getUserByUserId(responseScene.getUserId()).getData().getUserName();
                responseScene.setUserName(username);
            }

            SceneCooperation sceneCooperationEntity = sceneCooperationService.findBySceneNum(responseScene.getNum());
            if(sceneCooperationEntity != null){
                responseScene.setCooperationUserId(String.valueOf(sceneCooperationEntity.getUserId()));
                responseScene.setCooperationUserName(sceneCooperationService.findUserName(responseScene.getNum()));
            }
        });
        return pageInfo;
    }

    @Override
    public SceneCntDTO getSceneCnt(Long userId, Long cameraId) {

        //双目场景数量
        LambdaQueryWrapper<Scene> sceneWrapper =
            new LambdaQueryWrapper<Scene>()
                .eq(Scene::getUserId, userId);
        if(Objects.nonNull(cameraId)){
            sceneWrapper.eq(Scene::getCameraId, cameraId);
        }
        long sceneCount = sceneService.count(sceneWrapper);

        //八目场景数量
        LambdaQueryWrapper<ScenePro> sceneProWrapper =
            new LambdaQueryWrapper<ScenePro>()
                .select(ScenePro::getId)
                .eq(ScenePro::getUserId, userId);
        if(Objects.nonNull(cameraId)){
            sceneWrapper.eq(Scene::getCameraId, cameraId);
        }
        List<ScenePro> SceneProList = sceneProService.list(sceneProWrapper);
        long sceneProCount = 0;
        if(CollUtil.isNotEmpty(SceneProList)){
            List<Long> proIdList = SceneProList.stream().map(pro -> {
                return pro.getId();
            }).collect(Collectors.toList());
            sceneProCount = sceneProExtService.count(
                new LambdaQueryWrapper<SceneProExt>()
                    .eq(SceneProExt::getSceneSource,SceneSource.YJHZ.code())
                    .in(SceneProExt::getSceneProId, proIdList));
        }

        //协作场景数量
        long cooperaCount = sceneCooperationService.count(
            new LambdaQueryWrapper<SceneCooperation>().eq(SceneCooperation::getUserId, userId));

        return SceneCntDTO.builder().sceneCnt(sceneCount).sceneProCnt(sceneProCount).CooperSceneCnt(cooperaCount).build();
    }

    @Override
    public ResultData findSceneNumber(String token) throws Exception{
        SSOUser ssoUser = ssoLoginHelper.loginCheck(token);
        SceneNumVo sceneNumVoKk = getSceneNumVoByType(Arrays.asList(1,2,12,13,14), ssoUser.getId());
        sceneNumVoKk.setSceneNum( sceneNumVoKk.getSceneNum());
        sceneNumVoKk.setTotalNum(sceneNumVoKk.getTotalNum());

        SceneNumVo sceneNumVoKj = getSceneNumVoByType(Collections.singletonList(3), ssoUser.getId());
        SceneNumVo sceneNumVoSS = fdkkLaserService.getLaserSceneNumByUser(token);
        HashMap<String, SceneNumVo> hashMap = new HashMap<>();
        hashMap.put("kk",sceneNumVoKk);
        hashMap.put("kJ",sceneNumVoKj);
        hashMap.put("SS",sceneNumVoSS);
    return ResultData.ok(hashMap);
    }

    private SceneNumVo getSceneNumVoByType(List<Integer> sceneSourceList,Long userId){
        SceneNumVo sceneNumVo = new SceneNumVo();
        LambdaQueryWrapper<ScenePlus> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ScenePlus::getUserId, userId);
        queryWrapper.eq(ScenePlus::getSceneSource, sceneSourceList);
        Integer sceneNum = Math.toIntExact(scenePlusService.count(queryWrapper));
        sceneNumVo.setCooperationSceneNum(sceneCooperationService.getCooperationSceneNum(userId,sceneSourceList));
        sceneNumVo.setSceneNum(sceneNum);
        sceneNumVo.setTotalNum(sceneNumVo.getSceneNum() + sceneNumVo.getCooperationSceneNum());
        return sceneNumVo;
    }

    private Integer getSceneNumOld(Long userId) {
        LambdaQueryWrapper<Scene> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Scene::getUserId, userId);
        return Math.toIntExact(sceneService.count(queryWrapper));
    }

    @Override
    public ResultData getNewScenes(SceneParamVO param) throws Exception {

        Long userId = param.getUserId();
        if(param.getKeywordType().equals("userName") && StringUtils.isNotEmpty(param.getSearchKey())){

            ResultData<List<User>> userLikeUserName = platformUserClient
                .getUserLikeUserName("%" + param.getSearchKey() + "%");
            if(!userLikeUserName.getSuccess()){
                throw new Exception(ServerCode.FEIGN_REQUEST_FAILD.message());
            }
            List<User> userList = userLikeUserName.getData();
            List<Long> userIds = userList.parallelStream().map(User::getId).collect(Collectors.toList());

            List<SceneCooperation> sceneCooperationList = sceneCooperationService.list(
                new LambdaQueryWrapper<SceneCooperation>()
                    .select(SceneCooperation::getNum)
                    .in(SceneCooperation::getUserId, userIds));

            //获取所有协作场景的场景码集合
            param.setNumList(sceneCooperationList.parallelStream().map(SceneCooperation::getNum).collect(Collectors.toList()));

        }


        Map<String, Object> map = this.getNewScenesPagerByUserId(userId, param);
        Page<Object> page = (Page<Object>) map.get("pageInfo");
        List<Object> list = page.getRecords();
        list.parallelStream().filter(object -> object instanceof SceneVO).forEach(object -> {

            SceneVO responseScene = (SceneVO) object;
            // 当计算时，返回给前端的状态为计算中
            if (responseScene.getStatus() == -1) {
                responseScene.setStatus(0);
            } else if (responseScene.getStatus() == 500) {
                responseScene.setStatus(-1);
            }
            // 获取VrThumb
            SceneEditInfoExt sceneEditInfoExt
                = sceneEditInfoExtService.getOne(
                    new LambdaQueryWrapper<SceneEditInfoExt>()
                        .select(SceneEditInfoExt::getVrNum)
                        .eq(SceneEditInfoExt::getSceneProId, responseScene.getId()));

            if (!ObjectUtils.isEmpty(sceneEditInfoExt)) {
                responseScene.setVrNum(sceneEditInfoExt.getVrNum());
            }
            if (responseScene.getCameraId() != null) {
                ResultData<Camera> cameraResultData = platformGoodsClient
                    .getCameraById(responseScene.getCameraId());
                if(!cameraResultData.getSuccess()){
                    throw new BusinessException(ErrorCode.SYSTEM_BUSY);
                }
                Camera camera = cameraResultData.getData();
                if (camera != null) {
                    responseScene.setChildName(camera.getChildName());
                    responseScene.setSnCode(camera.getSnCode());
                }
            }
            SceneCooperation sceneCooperation = sceneCooperationService.findBySceneNum(responseScene.getNum());
            if (sceneCooperation != null) {
                responseScene.setCooperationUserId(String.valueOf(sceneCooperation.getUserId()));
                responseScene.setCooperationUserName(sceneCooperationService.findUserName(responseScene.getNum()));
            }
        });

        map.put("pageInfo", PageInfo.PageInfo(page));

        return ResultData.ok(map);
    }

    @Override
    public Integer getSceneNumByCameraId(Long cameraId,Integer cameraType,String snCode) {
        if(cameraType == 10){
            return fdkkLaserService.getLaserSceneNum(snCode);
        }
        Long cnt = sceneProService.findSceneNumByCameraId(cameraId);
        return Integer.parseInt(String.valueOf(cnt));
    }

    @Override
    public SceneProDTO getLastSceneByCameraId(Long cameraId) {
        SceneProPO sceneProPO = sceneProService.findLastSceneByCameraId(cameraId);
        return BeanUtil.copyProperties(sceneProPO, SceneProDTO.class);
    }

    @Override
    public ResultData downloadScene(Long userId, SceneDownloadParamVO param) throws Exception {

        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getSceneNum());
        if(scenePlus == null){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
        }

        SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
        if(sceneEditInfo == null){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
        }
        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByEditInfoId(sceneEditInfo.getId());

        Map<String, Object> result = new HashMap<>();

        ResultData<User> userResultData = platformUserClient.getUserByUserId(userId);
        if(!userResultData.getSuccess()){
            throw new Exception(ServerCode.FEIGN_REQUEST_FAILD.message());
        }
        User user = userResultData.getData();

        if(user != null || user.getDownloadNumTotal().compareTo(user.getDownloadNum()) < 1){
            result.put("downloadStatus", -1);
            ResultData.ok(result);
        }

        // 存储redis 开始下载任务
        String downLoadTaskJson = JSON.toJSONString(
            DownLoadTaskBean.builder()
                .num(param.getSceneNum())
                .type("local")
                .userId(userId).build());
        redisUtil.lRightPush(RedisKey.SCENE_DOWNLOADS_TASK_V4, downLoadTaskJson);

        SceneDownloadLog sceneDownloadLog = new SceneDownloadLog();
        sceneDownloadLog.setUserId(userId);
        sceneDownloadLog.setNum(param.getSceneNum());
        sceneDownloadLog.setSceneVersion(sceneEditInfo.getVersion());
        sceneDownloadLog.setDownloadStatus(DownloadStatus.DOWNLOADING.code());
        sceneDownloadLogService.save(sceneDownloadLog);

        result.put("downloadStatus", 1);
        return ResultData.ok(result);
    }

    @Override
    public ResultData getSceneDownloadProcess(Long userId, SceneDownloadParamVO param) {
        // 获取下载进度
        String processStr = redisUtil.get(String.format(RedisKey.PREFIX_DOWNLOAD_PROGRESS_V4, param.getSceneNum()));
        if (StringUtils.isEmpty(processStr)) {
            return ResultData.ok(
                DownLoadProgressBean.builder()
                    .status(SceneDownloadProgressStatus.DOWNLOADING.code())
                    .percent(0).url("").build());
        }
        return ResultData.ok(JSON.parseObject(processStr, DownLoadProgressBean.class));
    }

    @Override
    public ResultData checkDownload(Long userId, SceneDownloadParamVO param) throws Exception {

        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getSceneNum());
        if(scenePlus == null){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
        }

        SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
        if(sceneEditInfo == null){
            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
        }

        Map<String, Object> result = new HashMap<>();

        //downloadStatus,1打包资源下载，2已下载过，3下载过，并且没有修改过，无需打包直接返回下载地址，-1没下载次数不足
        //下载中
        SceneDownloadLog sceneDownloadLog = sceneDownloadLogService.findLastOneByNum(param.getSceneNum());

        //未下载过
        if(Objects.isNull(sceneDownloadLog)){
            result.put("downloadStatus", 0);
            return ResultData.ok(result);
        }

        if(sceneDownloadLog.getDownloadStatus() == DownloadStatus.DOWNLOADING.code()){
            result.put("downloadStatus", 1);
            return ResultData.ok(result);
        }


        //下载过，并且没有修改过
        if(sceneDownloadLog.getSceneVersion() == sceneEditInfo.getVersion()
            && sceneDownloadLog.getDownloadStatus() == DownloadStatus.SUCCESS.code()){

            result.put("downloadStatus", 3);
            result.put("downloadUrl", sceneDownloadLog.getDownloadUrl());
            return ResultData.ok(result);
        }

        //下载过,且修改过
        result.put("downloadStatus", 2);
        // 清除旧的下载信息
        redisUtil.del(String.format(RedisKey.PREFIX_DOWNLOAD_PROGRESS_V4, param.getSceneNum()));

        return ResultData.ok(result);

    }

    public Map<String, Object> getNewScenesPagerByUserId(Long userId, SceneParamVO param) throws Exception {

        List<SceneProPO> sceneList = new ArrayList<>();
        List<Folder> folderList = new ArrayList<>();

        boolean searchCamera = false;
        List<Camera> cameraList = new ArrayList<>();

        String sceneName = "";
        if (StringUtils.isNotEmpty(param.getKeywordType())) {
            if (param.getKeywordType().equals("sceneName")) {
                sceneName = param.getSearchKey();
            } else if (param.getKeywordType().equals("snCode") && Objects
                .nonNull(param.getSearchKey())) {
                ResultData<List<Camera>> cameraResult = platformGoodsClient
                    .getCameraLikeSnCode(param.getSearchKey());
                if (!cameraResult.getSuccess())
                    throw new Exception(ServerCode.FEIGN_REQUEST_FAILD.message());
                cameraList = cameraResult.getData();
                searchCamera = true;

            }

        }

        //根目录时，需要排除已经归类的场景
        if(param.getFolderId() == null){
            //查出所有已经归类的场景id
            List<Folder> allFolderList = folderService.list(
                                    new LambdaQueryWrapper<Folder>()
                                        .eq(Folder::getUserId, param.getUserId())
                                        .eq(Folder::getFolderType, param.getFolderType()));

            folderList = allFolderList.parallelStream().filter(folder->ObjectUtils.isEmpty(folder.getParentId())).collect(Collectors.toList());
            // 查找所有的文件夹
            List<Long> folderIds = allFolderList.parallelStream().map(Folder::getId).collect(Collectors.toList());
            List<Long> sceneIdList = new ArrayList<>();
            if(CollUtil.isNotEmpty(folderIds)){
                List<FolderScene> folderSceneList = folderSceneService.list(
                            new LambdaQueryWrapper<FolderScene>()
                                .select(FolderScene::getSceneId)
                                .in(FolderScene::getFolderId, folderIds));
                sceneIdList = folderSceneList.parallelStream().map(FolderScene::getSceneId).collect(Collectors.toList());
            }

            if(sceneIdList.size() > 0){
                param.setSceneIdList(sceneIdList);
            }

            //协作者 检索
            if(param.getKeywordType().equals("userName") && StringUtils.isNotEmpty(param.getSearchKey())){
                if(CollUtil.isEmpty(param.getNumList())){
                    param.setNum("");
                }
            }

            if(StrUtil.isNotBlank(param.getSceneSource())){
                param.setSceneSourceList(ParamConvertUtil.getSceneSource(param.getSceneSource()));
            }

            if(searchCamera){
                if(CollUtil.isEmpty(cameraList)){
                    sceneList = new ArrayList<>();
                }else{
                    param.setCameraIdList(cameraList.stream().map(Camera::getId).collect(Collectors.toList()));
                    sceneList = sceneProMapper.selectSceneList(param);
                }
            }else{
                sceneList = sceneProMapper.selectSceneList(param);
            }

        }else {
            //进入目录层级后，根据目录获取当前目录的所有场景
            List<Long> sceneIdList = folderSceneService
                .getSceneIdListByFolderId(param.getFolderId());

            if(StrUtil.isNotBlank(param.getSceneSource())){
                param.setSceneSourceList(ParamConvertUtil.getSceneSource(param.getSceneSource()));
            }
            if(CollUtil.isNotEmpty(sceneIdList)){
                param.setSceneIdList(sceneIdList);
                if(searchCamera){
                    if(CollUtil.isEmpty(cameraList)){
                        sceneList = new ArrayList<>();
                    }else{
                        param.setCameraIdList(cameraList.stream().map(Camera::getId).collect(Collectors.toList()));
                        sceneList = sceneProMapper.selectSceneList(param);
                    }
                }else{
                    sceneList = sceneProMapper.selectSceneList(param);
                }
            }

            //获取文件夹数量
            folderList= folderService.list(
                new LambdaQueryWrapper<Folder>().eq(Folder::getUserId, param.getUserId())
                    .eq(Folder::getParentId, param.getFolderId())
                    .orderByDesc(Folder::getId));
        }
        List<SceneVO> responseScenes = sceneService.convertPro(sceneList);

        //当前文件夹所包含的所有场景数量
        Long sceneNum = 0L;
        List<FolderVO> responseFolderList = new ArrayList<>();

        List<Object> result = new ArrayList<>();
        if(Objects.nonNull(param.getSceneSource()) && StrUtil.isEmpty(param.getSceneType()) &&
            param.getStartTime() == null && param.getEndTime() == null){

            responseFolderList = folderService.convert(folderList);
            result.addAll(responseFolderList);

            //根目录判断是否有双目文件夹
            if(param.getFolderId() == null && param.getSceneSource().contains("1")){
                //判断是否有双目场景，有则增加双目的文件夹
                Long sceneCnt = sceneService
                    .count(new LambdaQueryWrapper<Scene>().eq(Scene::getUserId, userId));

                if(sceneCnt > 0){
                    FolderVO sceneFolder = new FolderVO();
                    sceneFolder.setName("双目文件夹");
                    //type为3，表示旧版双目相机场景
                    sceneFolder.setType(3);
                    sceneFolder.setIsFolder(1);
                    sceneFolder.setSceneNum(Integer.parseInt(String.valueOf(sceneCnt)));
                    result.add(sceneFolder);
                }
            }
        }

        //统计当前目录所有场景数量
        sceneNum += responseFolderList.parallelStream().mapToLong(FolderVO::getSceneNum).sum();
        sceneNum += sceneList.size();
        sceneNum += responseScenes.size();
        result.addAll(responseScenes);

        Page<Object> data = PageInfoUtils.list2PageInfo(result, param.getPageNum(), param.getPageSize());

        Map<String, Object> map = new HashMap<>();
        map.put("sceneNum",  sceneNum);
        map.put("pageInfo", data);
        return map;
    }
}
