package com.fdkankan.ucenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fdkankan.common.constant.Constant;
import com.fdkankan.ucenter.common.CameraTypeEnum;
import com.fdkankan.ucenter.common.constants.NacosProperty;
import com.fdkankan.ucenter.entity.*;
import com.fdkankan.ucenter.httpClient.service.LaserService;
import com.fdkankan.ucenter.mapper.ICameraDetailMapper;
import com.fdkankan.ucenter.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fdkankan.ucenter.vo.response.CameraAppVo;
import com.fdkankan.ucenter.vo.response.CameraExcelVo;
import com.fdkankan.ucenter.vo.response.CameraSpaceVo;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * <p>
 * 相机子表 服务实现类
 * </p>
 *
 * @author 
 * @since 2022-07-04
 */
@Service
public class CameraDetailServiceImpl extends ServiceImpl<ICameraDetailMapper, CameraDetail> implements ICameraDetailService {

    @Autowired
    IUserService userService;
    @Autowired
    ICameraSpaceService cameraSpaceService;
    @Autowired
    LaserService fdkkLaserService;
    @Autowired
    ICameraService cameraService;
    @Autowired
    ISceneCooperationService sceneCooperationService;
    @Autowired
    ISceneProService sceneProService;
    @Autowired
    IScenePlusService scenePlusService;
    @Autowired
    IUserIncrementService userIncrementService;
    @Autowired
    IIncrementTypeService incrementTypeService;
    @Autowired
    IFolderSceneService folderSceneService;
    @Autowired
    ICameraTypeService cameraTypeService;

    @Override
    public CameraDetail getByCameraId(Long cameraId) {
        LambdaQueryWrapper<CameraDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CameraDetail::getCameraId,cameraId);
        List<CameraDetail> list = this.list(wrapper);
        if(list!=null && list.size() >0){
            return list.get(0);
        }
        return null;
    }

    @Override
    public HashMap<Long, CameraDetail> getByCameraIds(List<Long> cameraIds) {
        HashMap<Long, CameraDetail> map = new HashMap<>();
        if(cameraIds.size() >0){
            LambdaQueryWrapper<CameraDetail> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(CameraDetail::getCameraId,cameraIds);
            List<CameraDetail> list = this.list(wrapper);
            list.forEach(entity -> map.put(entity.getCameraId(),entity));
        }
        return map;
    }

    @Override
    public Long getCountByUserId(Long userId,Integer type) {
        LambdaQueryWrapper<CameraDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CameraDetail::getUserId,userId);
        if(type != null){
            wrapper.eq(CameraDetail::getType,type);
        }
        return this.count(wrapper);
    }

    @Override
    public Integer deadlineNumber(String username) {
        User user = userService.getByUserName(username);
        QueryWrapper<CameraDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(CameraDetail::getUserId,user.getId());
        List<CameraDetail> list = this.list(queryWrapper);
        Integer number = 0;
        List<CameraSpaceVo> cameraList = null;
        for (CameraDetail cameraDetailEntity : list) {
            cameraList = cameraSpaceService.getVoListByCameraId(cameraDetailEntity.getCameraId());
            if(cameraList != null && cameraList.size() > 0){
                if(Days.daysBetween(new DateTime(), new DateTime(cameraList.get(0).getSpaceEndTime())).getDays() < 30){
                    number++;
                }
            }
        }
        return number;
    }

    @Override
    public void unbindCamera(List<Long> cameraIds) {
        HashMap<Long, CameraDetail> detailMap = this.getByCameraIds(cameraIds);
        HashMap<Long, Camera> cameraMap = cameraService.getByIds(cameraIds);
        for (CameraDetail cameraDetail : detailMap.values()) {
            LambdaUpdateWrapper<CameraDetail> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(CameraDetail::getId,cameraDetail.getId());
            wrapper.set(CameraDetail::getUserId,null);
            wrapper.set(CameraDetail::getCooperationUser,null);
            this.update(wrapper);
            CameraType cameraType = cameraTypeService.getByCameraType(cameraDetail.getType());

            //国内服解绑
            if(!"aws".equals(NacosProperty.uploadType) && !"local".equals(NacosProperty.uploadType) && cameraType.getIsLaser() ==0){
                sceneProService.lockOrUnLockBySpace(cameraDetail,cameraDetail.getCameraId());     //封存场景
            }
            //国际服解绑
            if("aws".equals(NacosProperty.uploadType) ){
                sceneProService.lockOrUnLockBySpace(cameraDetail,cameraDetail.getCameraId());     //封存场景
            }
            if (cameraType.getIsLaser() == 1) {
                fdkkLaserService.toBind(false,cameraMap.get(cameraDetail.getCameraId()).getSnCode(),null,null);
            }
        }
        //恢复10G基本容量

        //删除场景协作信息
        List<ScenePro> sceneProList = sceneProService.getListByCameraIds(cameraIds);
        List<ScenePlus> scenePlusList = scenePlusService.getListByCameraIds(cameraIds);
        sceneCooperationService.deleteCooperationList(sceneProList,scenePlusList,null);
        fdkkLaserService.disableCooperation(detailMap, cameraMap);
        //解绑删除相机。文件夹与场景绑定关系
        List<Long > sceneIds = new ArrayList<>();
        if(sceneProList.size() >0){
            List<Long> proIds = sceneProList.stream().map(ScenePro::getId).collect(Collectors.toList());
            if(proIds.size() >0){
                sceneIds.addAll(proIds);
            }
        }
        if(scenePlusList.size() >0){
            List<Long> plusIds = scenePlusList.stream().map(ScenePlus::getId).collect(Collectors.toList());
            if(plusIds.size() >0){
                sceneIds.addAll(plusIds);
            }
        }
        if(sceneIds.size() >0){
            folderSceneService.delBySceneId(sceneIds);
        }
    }

    @Override
    public void bindCamera(List<Long> cameraIds,User user) {
        if(cameraIds.size() >0){
            LambdaUpdateWrapper<CameraDetail> wrapper = new LambdaUpdateWrapper<>();
            wrapper.in(CameraDetail::getCameraId,cameraIds)
                    .set(CameraDetail::getUserId,user.getId());
            this.update(wrapper);

            HashMap<Long, CameraDetail> detailMap = this.getByCameraIds(cameraIds);
            HashMap<Long, Camera> cameraMap = cameraService.getByIds(cameraIds);
            for (CameraDetail cameraDetail : detailMap.values()) {
                CameraType cameraType = cameraTypeService.getByCameraType(cameraDetail.getType());
                if (cameraType.getIsLaser() == 1) {
                    fdkkLaserService.toBind(true,cameraMap.get(cameraDetail.getCameraId()).getSnCode(),user.getUserName(),user.getId());
                }
            }
        }


    }

    @Override
    public void updateCooperationByIds(List<Long> cameraIds, Long userId) {
        LambdaUpdateWrapper<CameraDetail> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(CameraDetail::getCameraId,cameraIds)
                .set(CameraDetail::getCooperationUser,userId);
        this.update(wrapper);
    }

    @Override
    public void addUsedSpace(HashMap<Long, Long> cameraMap) {
        Set<Long> cameraIds = cameraMap.keySet();
        LambdaQueryWrapper<CameraDetail> wrapper = new LambdaQueryWrapper<>();
        if(cameraIds.isEmpty()){
            return;
        }
        wrapper.in(CameraDetail::getCameraId,cameraIds);
        List<CameraDetail> list = this.list(wrapper);
        for (CameraDetail cameraDetail : list) {
            //解封封存场景
            sceneProService.lockOrUnLockBySpace(cameraDetail,cameraDetail.getCameraId());
            this.initSpace(cameraDetail);
        }
    }

    @Override
    public void addUsedSpace(CameraDetail cameraDetail,Long space) {
        if("SP".equals(cameraDetail.getUnit())){
            space = 1L;
        }
        LambdaUpdateWrapper<CameraDetail> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(CameraDetail::getId,cameraDetail.getId());
        wrapper.setSql("used_space =  used_space + " + space);
        this.update(wrapper);
    }
    public void subUsedSpace(CameraDetail cameraDetail,Long space) {
        if("SP".equals(cameraDetail.getUnit())){
            space = 1L;
        }
        LambdaUpdateWrapper<CameraDetail> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(CameraDetail::getId,cameraDetail.getId());
        wrapper.setSql("used_space =  used_space - " + space);
        this.update(wrapper);
    }

    @Override
    public List<CameraAppVo> getListByUserAndType(Long userId, Integer cameraType) {
        return this.getBaseMapper().getListByUserAndType(userId,cameraType);
    }
    @Override
    public List<CameraAppVo> getListByUserIdsAndType(List<Long> userId, Integer cameraType) {
        return this.getBaseMapper().getListByUserIdsAndType(userId,cameraType);
    }

    @Override
    public boolean updateCameraBalance(Long cameraId, int body, Integer points) {
        CameraDetail detailEntity = this.getByCameraId(cameraId);
        int sub = Integer.parseInt(detailEntity.getBalance());
        if (0 == body){
            sub += points;
        }else if (-2 == body){
            sub -= points;
        }
        detailEntity.setBalance(String.valueOf(sub));
        return this.updateById(detailEntity);
    }

    @Override
    public void uploadUserCameraInfo(Long id, String cameraVersion, String appVersion) {
        LambdaUpdateWrapper<CameraDetail> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(CameraDetail::getCameraId,id)
                .set(CameraDetail::getUserCameraVersion,cameraVersion)
                .set(CameraDetail::getAppVersion,appVersion)
                .set(CameraDetail::getLastRequestTime,new Date());
        this.update(wrapper);
    }

    @Override
    public List<CameraExcelVo> getListByUserAndTypeEx(Long userId) {
        return this.getBaseMapper().getListByUserAndTypeEx(userId);
    }


    @Override
    public Long getTotalSpaceByCameraId(CameraDetail cameraDetail) {
        CameraType cameraType = cameraTypeService.getByCameraType(cameraDetail.getType());
        if (!"aws".equals(NacosProperty.uploadType) && cameraType.getIsLaser() == 1) {
            return -1L;
        }
        UserIncrement userIncrement = userIncrementService.getByCameraId(cameraDetail.getCameraId());
        if(userIncrement != null && userIncrement.getIsExpired() == 0){
            IncrementType incrementType = incrementTypeService.getById(userIncrement.getIncrementTypeId());
            return getTotalSpace(cameraDetail,incrementType);
        }
        return getTotalSpace(cameraDetail,null);
    }


    @Override
    public Boolean checkSpace(Long cameraId, CameraType cameraType) {
        CameraDetail detailEntity = this.getByCameraId(cameraId);
        if(detailEntity == null){
            return false;
        }
        return checkSpace(detailEntity,cameraType);
    }

    @Override
    public Boolean checkSpace(CameraDetail detailEntity, CameraType cameraType) {
        if (!"aws".equals(NacosProperty.uploadType) && cameraType.getIsLaser() == 1) {
            return true;
        }
        UserIncrement userIncrement = userIncrementService.getByCameraId(detailEntity.getCameraId());
        if(userIncrement == null || userIncrement.getIsExpired() == 1){
            return checkSpace(detailEntity,null,cameraType,true);
        }
        IncrementType incrementType = incrementTypeService.getById(userIncrement.getIncrementTypeId());
        return checkSpace(detailEntity,incrementType,cameraType,true);
    }

    @Override
    public Boolean checkSpace(CameraDetail detailEntity, IncrementType incrementType, Long space,CameraType cameraType) {
        Long totalSpace = 0L;
        if (!"aws".equals(NacosProperty.uploadType) && cameraType.getIsLaser() == 1) {
            return true;
        }
        if("SP".equals(detailEntity.getUnit())){
            if(incrementType!=null && incrementType.getCameraSpace() == -1){
                return true;
            }
            totalSpace = incrementType != null ?incrementType.getCameraSpace() : detailEntity.getTotalSpace();
            Long proCount = sceneProService.getCountByCameraId(detailEntity.getCameraId());
            Long plusCount = scenePlusService.getCountByCameraId(detailEntity.getCameraId());
            return proCount + plusCount + 1 <= totalSpace;
        }
        if("GB".equals(detailEntity.getUnit())){
            if(incrementType!=null && incrementType.getCameraCapacity() == -1){
                return true;
            }
            totalSpace = incrementType != null ?incrementType.getCameraCapacity()  * 1024 * 1024 * 1024L: detailEntity.getTotalSpace();
            return detailEntity.getUsedSpace() + space <= totalSpace;
        }
        return false;
    }

    public Boolean checkSpace(CameraDetail detailEntity, IncrementType incrementType,CameraType cameraType,Boolean falg) {
        Long totalSpace = 0L;
        if (!"aws".equals(NacosProperty.uploadType) && cameraType.getIsLaser() == 1) {
            return true;
        }
        if("SP".equals(detailEntity.getUnit())){
            if(incrementType!=null && incrementType.getCameraSpace() == -1){
                return true;
            }
            totalSpace = incrementType != null ?incrementType.getCameraSpace() : detailEntity.getTotalSpace();
            Long proCount = sceneProService.getCountByCameraId(detailEntity.getCameraId());
            Long plusCount = scenePlusService.getCountByCameraId(detailEntity.getCameraId());
            return proCount + plusCount  <= totalSpace;
        }
        if("GB".equals(detailEntity.getUnit())){
            if(incrementType!=null && incrementType.getCameraCapacity() == -1){
                return true;
            }
            totalSpace = incrementType != null ?incrementType.getCameraCapacity()  * 1024 * 1024 * 1024L: detailEntity.getTotalSpace();
            return detailEntity.getUsedSpace()  <= totalSpace;
        }
        return false;
    }

    public Long getTotalSpace(CameraDetail detailEntity, IncrementType incrementType) {
        if("SP".equals(detailEntity.getUnit())){
            if(incrementType!=null && incrementType.getCameraSpace() == -1){
                return -1L;
            }
            return incrementType != null ?incrementType.getCameraSpace() : detailEntity.getTotalSpace();
        }
        if("GB".equals(detailEntity.getUnit())){
            if(incrementType!=null && incrementType.getCameraCapacity() == -1){
                return -1L;
            }
            return incrementType != null ?incrementType.getCameraCapacity() * 1024 * 1024 * 1024L : detailEntity.getTotalSpace();
        }
        return 0L;
    }

    @Override
    public void initSpace(Long cameraId) {
        CameraDetail cameraDetail = this.getByCameraId(cameraId);
        if(cameraDetail != null){
            initSpace(cameraDetail);
        }
    }

    @Override
    public void initSpace(CameraDetail cameraDetail) {
        LambdaUpdateWrapper<CameraDetail> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(CameraDetail::getId,cameraDetail.getId());
        if("GB".equals(cameraDetail.getUnit())){
            Long proSpace = sceneProService.getSpaceSumByCameraId(cameraDetail.getCameraId());
            Long plusSpace = scenePlusService.getSpaceSumByCameraId(cameraDetail.getCameraId());
            wrapper.set(CameraDetail::getUsedSpace,(plusSpace == null ?0L:plusSpace) + (proSpace == null ?0L:proSpace));
        }
        if("SP".equals(cameraDetail.getUnit())){
            Long proSpace = sceneProService.getCountByCameraId(cameraDetail.getCameraId(),true);
            Long plusSpace = scenePlusService.getCountByCameraId(cameraDetail.getCameraId(),true);
            wrapper.set(CameraDetail::getUsedSpace,(plusSpace == null ?0L:plusSpace )+( proSpace == null ?0L:proSpace));
        }
        this.update(wrapper);
    }
}
