package com.fdkankan.ucenter.service.impl;

import com.alibaba.fastjson.JSONObject;
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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fdkankan.common.constant.ConstantRegex;
import com.fdkankan.common.constant.ConstantUrl;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.util.*;
import com.fdkankan.fyun.face.FYunFileServiceInterface;
import com.fdkankan.ucenter.common.constants.ConstantFilePath;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.util.RedisUtil;
import com.fdkankan.sensitive.Variable;
import com.fdkankan.ucenter.common.constants.NacosProperty;
import com.fdkankan.ucenter.constant.LoginConstant;
import com.fdkankan.ucenter.entity.*;
import com.fdkankan.ucenter.mapper.IUserIncrementMapper;
import com.fdkankan.ucenter.mapper.IUserMapper;
import com.fdkankan.ucenter.service.*;
import com.fdkankan.ucenter.util.DateUserUtil;
import com.fdkankan.ucenter.vo.request.RegisterParam;
import com.fdkankan.ucenter.vo.request.ShipAddressParam;
import com.fdkankan.ucenter.vo.request.UserParam;
import com.fdkankan.ucenter.vo.response.*;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author 
 * @since 2022-07-01
 */
@Service
public class UserServiceImpl extends ServiceImpl<IUserMapper, User> implements IUserService {

    @Value("${fyun.host}")
    private String osssPrefixUrl;

    @Autowired
    ICameraDetailService cameraDetailService;
    @Autowired
    IUserIncrementService userIncrementService;
    @Autowired
    IIncrementTypeService incrementTypeService;
    @Autowired
    IReceiverInfoService receiverInfoService;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    FYunFileServiceInterface fYunFileService;
    @Autowired
    ICameraService cameraService;
    @Autowired
    ICameraSpaceService cameraSpaceService;
    @Autowired
    ICameraTypeService cameraTypeService;
    @Autowired
    ISceneProService sceneProService;
    @Autowired
    IScenePlusService scenePlusService;

    private User getByEmail(String email){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(User ::getEmail,email);
        List<User> list = this.list(queryWrapper);
        if(list == null || list.size()<=0){
            return null;
        }
        return list.get(0);
    }

    @Override
    public User getByUserName(String phoneNum) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserName,phoneNum);
        List<User> list = this.list(wrapper);
        if(list != null && list.size() >0){
            return list.get(0);
        }
        return null;
    }

    @Override
    public User register(RegisterParam param) {
        User userEntity = new User();
        userEntity.setPassword(SecurityUtil.MD5(param.getPassword()));
        userEntity.setEmail(param.getEmail());
        userEntity.setUserName(param.getPhoneNum());
        userEntity.setNickName(param.getPhoneNum());
        userEntity.setHead(ConstantUrl.DEFAULT_USER_HEAD);
        userEntity.setCountry(param.getCountry());
        userEntity.setStatus(1);
        userEntity.setIsNotice(1);
        userEntity.setRecStatus("A");
        userEntity.setCreateTime(DateUserUtil.getDate(new Date()));
        userEntity.setUpdateTime(DateUserUtil.getDate(new Date()));
        userEntity.setAgentKey(param.getAgentKey());
        this.save(userEntity);
        return userEntity;
    }

    @Override
    public void updatePassword(String phoneNum, String password) {
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(User::getPassword,password)
                .eq(User::getUserName,phoneNum);
        this.update(wrapper);
    }

    @Override
    public UserVo getUserInfo(String userName) {
        User user = this.getByUserName(userName);
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user,userVo);
        Long cameraCount = cameraDetailService.getCountByUserId(user.getId(),null);
        Long incrementNum = userIncrementService.getCountByUserId(user.getId(),0);
        Long incrementBindNum = userIncrementService.getCountByUserId(user.getId(),1);
        userVo.setCameraCount(cameraCount);
        userVo.setIncrementNum(incrementNum);
        userVo.setIncrementBindNum(incrementBindNum);
        return userVo;
    }

    @Override
    public String uploadHead(String imgdata, String userName) throws Exception {
        if (StringUtils.isEmpty(imgdata)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        User dbUser = this.getByUserName(userName);
        StringBuilder sb = new StringBuilder().append("head")
                .append(File.separator).append(dbUser.getUserName()).append(File.separator)
                .append("head").append("_").append(new Date().getTime()).append(".png");
        StringBuilder qiniuPath = new StringBuilder().append("head")
                .append("/").append(dbUser.getUserName()).append("/")
                .append("head").append("_").append(new Date().getTime()).append(".png");
        FileUtils.uploadImg(ConstantFilePath.USER_IMAGES_PATH + sb.toString(), imgdata);
        byte[] imageByte = FileUtils.getImageByte(imgdata);
        //上传头像到oss
        fYunFileService.uploadFile(imageByte, qiniuPath.toString());

        dbUser.setHead(osssPrefixUrl + qiniuPath.toString()+"?m="+System.currentTimeMillis());
        this.updateById(dbUser);

        return dbUser.getHead();
    }

    @Override
    public void insertAddress(ShipAddressParam param, String userName) {
        if (StringUtils.isEmpty(param.getShipAddress()) || StringUtils.isEmpty(param.getShipAreaPath())
                || StringUtils.isEmpty(param.getProvince()) || StringUtils.isEmpty(param.getCity())){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        User user = getByUserName(userName);
        receiverInfoService.saveByParam(param,user.getId());
    }

    @Override
    public void updateAddress(ShipAddressParam param, String userName) {
        if (param.getId() == null || StringUtils.isEmpty(param.getShipAddress()) || StringUtils.isEmpty(param.getShipAreaPath())
                || StringUtils.isEmpty(param.getProvince()) || StringUtils.isEmpty(param.getCity())){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        User user = getByUserName(userName);
        receiverInfoService.updateDefaultAddress(param,user.getId());
    }

    @Override
    public void deleteAddress(Long id) {
        if (id == null ){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        receiverInfoService.removeById(id);
    }

    @Override
    public void updateEmail(String email, String userName) {
        if (StringUtils.isEmpty(email)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        if(!email.matches(ConstantRegex.EMAIL_REGEX)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3019, LoginConstant.FAILURE_MSG_3019);
        }
        User user = this.getByEmail(email);
        if(user!=null && !user.getUserName().equals(userName)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3020 , LoginConstant.FAILURE_MSG_3020);
        }
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getUserName,userName);
        wrapper.set(User::getEmail,email);
        this.update(wrapper);
    }

    @Override
    public ReceiverInfo getReceiverInfo(String userName) {
        User dbUser = getByUserName(userName);
        return receiverInfoService.getDefaultByUserId(dbUser.getId());
    }

    @Override
    public List<ReceiverInfo> getReceiverList(String userName) {
        User dbUser = getByUserName(userName);
        return receiverInfoService.getListByUserId(dbUser.getId());
    }

    @Override
    public void updateNickName(String nickName, String userName) {
        if (StringUtils.isEmpty(nickName)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        //检验昵称敏感词
        Set<String> set = Variable.sensitiveWord.getSensitiveWord(nickName, 1);
        if (set != null && set.size() > 0){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3012, LoginConstant.FAILURE_MSG_3012);
        }
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getUserName,userName);
        wrapper.set(User::getNickName,nickName);
        this.update(wrapper);
    }

    @Override
    public void updateUserDetail(UserParam param, String userName) {
        if (param.getNickName() != null){
            //检验昵称敏感词
            Set<String> set = Variable.sensitiveWord.getSensitiveWord(param.getNickName(), 1);
            if (set != null && set.size() > 0){
                throw new BusinessException(LoginConstant.FAILURE_CODE_3012, LoginConstant.FAILURE_MSG_3012);
            }
        }

        if(param.getEmail() != null && !param.getEmail().matches(ConstantRegex.EMAIL_REGEX)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3019, LoginConstant.FAILURE_MSG_3019);
        }
        User emailUser = getByEmail(param.getEmail());
        if(emailUser != null && !emailUser.getUserName().equals(userName)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3020 , LoginConstant.FAILURE_MSG_3020);
        }
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getUserName,userName);
        wrapper.set(User::getNickName,param.getNickName());
        wrapper.set(User::getEmail,param.getEmail());
        wrapper.set(User::getIsNotice,param.getIsNotice());
        this.update(wrapper);
    }

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

    @Override
    public Long getCountByNickName(String nickName) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getNickName,nickName);
        return this.count(wrapper);
    }

    @Override
    public List<Long> getLikeUserName(String userName) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(User::getUserName,userName);
        List<Long> collect = this.list(wrapper).parallelStream().map(User::getId).collect(Collectors.toList());
        return new ArrayList<>(collect);
    }

    @Override
    public User getByToken(String token) {
        try {
            String value = redisUtil.get(String.format(RedisKey.TOKEN_V3, token));
            if(StringUtils.isEmpty(value)){
                throw new Exception();
            }
            return JSONObject.parseObject(value,User.class);
        }catch (Exception e){
            e.printStackTrace();
        }
        String username = JwtUtil.getUsername(token);
        return this.getByUserName(username);
    }

    @Override
    public CameraVo findCameraDetailByChildName(String token, String childName) {
        CameraVo cameraVo = cameraService.getVoByChildName(childName);
        if(cameraVo == null){
            return null;
        }
        User userVo = this.getByToken(token);
        if(userVo != null && userVo.getId()!= null){
            User user = this.getById(userVo.getId());
            cameraVo.setNickName(user.getNickName());
            cameraVo.setNickNameEn(user.getNickName());
        }else {
            switch (cameraVo.getType()){
                case 9 :   cameraVo.setNickName("Minion设备用户") ; cameraVo.setNickNameEn("4DMinion user") ;break;
                case 10 :  cameraVo.setNickName("四维深时用户"); cameraVo.setNickNameEn("4DMega user"); break;
                case 11 :  cameraVo.setNickName("四维深光用户");cameraVo.setNickNameEn("4DMeta user"); break;
                default:  cameraVo.setNickName("Pro设备用户");cameraVo.setNickNameEn("4DKanKan user"); break;
            }
        }

        //获取会员权益
        UserIncrement userIncrement = userIncrementService.getByCameraId(cameraVo.getId());
        if(userIncrement != null){
            ResponseUserIncrement responseUserIncrement = new ResponseUserIncrement();
            BeanUtils.copyProperties(userIncrement,responseUserIncrement);
            cameraVo.setResponseUserIncrement(responseUserIncrement);
            cameraVo.setMemberLevels(userIncrement.getMemberLevels());
            IncrementType incrementType = incrementTypeService.getById(userIncrement.getIncrementTypeId());
            if(incrementType != null && userIncrement.getIsExpired() == 0){
                if("GB".equals(cameraVo.getUnit())){
                    cameraVo.setTotalSpace(String.valueOf(incrementType.getCameraCapacity()));
                    cameraVo.setTotalSpaceStr(incrementType.getCameraCapacity()+".00GB");
                }
                if("SP".equals(cameraVo.getUnit())){
                    cameraVo.setTotalSpace(String.valueOf(incrementType.getCameraSpace()));
                    cameraVo.setTotalSpaceStr(String.valueOf(incrementType.getCameraSpace()));
                }
            }

        }
        return cameraVo;
    }

    @Override
    public void updateDownloadNum(long userId, int num) {
        this.update(new LambdaUpdateWrapper<User>().setSql("download_num = download_num + " + num).eq(User::getId, userId));
    }
}
