package com.ruoyi.xq.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.BeanConvertUtil;
import com.ruoyi.xq.domain.*;
import com.ruoyi.xq.dto.admin.user.FullUserVo;
import com.ruoyi.xq.dto.admin.user.UserAdminVo;
import com.ruoyi.xq.dto.admin.user.req.AddUserReq;
import com.ruoyi.xq.dto.admin.user.req.UpdateMobileAdminReq;
import com.ruoyi.xq.dto.admin.user.req.UpdateUserReq;
import com.ruoyi.xq.dto.app.user.HomePageReq;
import com.ruoyi.xq.dto.app.user.vo.HomeUserListVo;
import com.ruoyi.xq.dto.app.user.vo.HomeUserVo;
import com.ruoyi.xq.dto.app.user.vo.UserAuthMinVo;
import com.ruoyi.xq.dto.common.user.MinUser;
import com.ruoyi.xq.enums.ErrorEnum;
import com.ruoyi.xq.enums.common.AuditEnum;
import com.ruoyi.xq.enums.common.SystemConfigEnum;
import com.ruoyi.xq.enums.image.ImagesEnums;
import com.ruoyi.xq.enums.userinfo.UserGenderEnum;
import com.ruoyi.xq.lock.LockKey;
import com.ruoyi.xq.manager.LoginManager;
import com.ruoyi.xq.manager.SystemConfigManager;
import com.ruoyi.xq.mapper.UserMapper;
import com.ruoyi.xq.service.*;
import com.ruoyi.xq.util.AgeUtil;
import com.ruoyi.xq.util.BirthdayUtil;
import com.ruoyi.xq.util.ShowAvatarUtil;
import com.ruoyi.yunxin.client.ImUserRefClient;
import com.ruoyi.yunxin.req.UpdateUinfoReq;
import com.ruoyi.yunxin.resp.YxCommonR;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 用户管理Service业务层处理
 *
 * @author 77
 * @date 2024-03-04
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private UserLoginService userLoginService;
    @Resource
    private ImUserRefClient userRefClient;
    @Autowired
    private SystemConfigManager systemConfigManager;
    @Autowired
    private UserPicturesService userPicturesService;
    @Autowired
    private UserVipService userVipService;
    @Autowired
    private UserAuthService userAuthService;
    @Autowired
    private UserStatusService userStatusService;
    @Autowired
    private UserExtendService userExtendService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private AreaCodeService areaCodeService;
    @Autowired
    private UserStarService userStarService;

    @Override
    public MinUser getMinUserById(Long userId){
        return baseMapper.getMinUserById(userId);
    }

    @Override
    public User getByUsername(String username) {
        return this.getOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getMobile,username));
    }

    @Override
    public void resetPassword(Long userId, String password) {
        if(userId == null || StringUtils.isEmpty(password)){
            throw new ServiceException("参数异常");
        }
        this.update(Wrappers.lambdaUpdate(User.class)
                .eq(User::getId,userId)
                .set(User::getPassword, BCrypt.hashpw(password)));
    }

    @Override
    public User getByUsercode(String usercode) {
        return this.getOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getUsercode,usercode).last("limit 1"));
    }

    @Override
    public HomeUserVo homeUser(Long userId) {
        User user = this.getById(userId);
        UserInfo userInfo = userInfoService.getByUserId(userId);
        HomeUserVo result = new HomeUserVo();
        BeanConvertUtil.copyProperties(userInfo,result);
        BeanConvertUtil.copyProperties(user,result);
        List<UserPictures> userPicturesList = userPicturesService.listByUserIdSuccess(userId);
        result.setUserPictureList(userPicturesList.stream().map(UserPictures::getPicture).collect(Collectors.toList()));
        result.setOpenVip(user.getOpenVip());
        result.setVipType(user.getVipType());
        UserAuth userAuth = userAuthService.getByUserId(userId);
        UserAuthMinVo authMinVo = BeanConvertUtil.convertTo(userAuth, UserAuthMinVo::new);
        result.setUserAuthInfo(authMinVo);
        Long currentUserId = LoginHelper.getUserId();
        if(userId.equals(currentUserId)){
            return result;
        }
        // TODO 登录时间
        boolean star = userStarService.existsStar(currentUserId, userId);
        result.setStar(star);
        UserStatus userStatus = userStatusService.getByUserId(userId);
        boolean showAvatar = this.showAvatar(LoginHelper.getUserId(), userStatus.getShowAvatar());
        if(!showAvatar){
            String cos = systemConfigManager.getSystemConfig(SystemConfigEnum.COS_DOMAIN);
            result.setAvatar(cos + ImagesEnums.PRIVACY_IMAGE.getPath());
            result.setShowAvatarBool(false);
            result.setUserPictureList(Collections.emptyList());
        }
        return result;
    }

    private boolean showAvatar(Long userId, Integer avatar){
        if(userId == null){
            return ShowAvatarUtil.showAvatar(false,false,avatar);
        }
        UserAuth userAuth = userAuthService.getByUserId(userId);
        User user = this.getById(userId);
        return ShowAvatarUtil.showAvatar(user.getOpenVip(),userAuth.getCarAuth()==1, avatar);
    }

    @Override
    public boolean updateMobileUser(UpdateMobileAdminReq bo) {
        if(!PhoneUtil.isMobile(bo.getMobile())){
            throw new ServiceException("请填写正常的手机号");
        }
        User user = this.getById(bo.getId());
        if(com.ruoyi.common.utils.StringUtils.isNotEmpty(bo.getMobile())){
            long count = this.count(Wrappers.lambdaQuery(User.class)
                    .eq(User::getMobile, bo.getMobile())
                    .ne(User::getId, user.getId()));
            if(count > 0){
                throw new BaseException("手机号已存在，无法修改");
            }
        }
        User update = new User();
        update.setId(user.getId());
        update.setMobile(bo.getMobile());
        this.updateById(update);
        return true;
    }


    @Override
    public void resetAvatar(Long userId) {
        User user = this.getById(userId);
        if(user == null){
            return;
        }
        String cos = systemConfigManager.getSystemConfig(SystemConfigEnum.COS_DOMAIN);
        Integer gender = user.getGender();
        UserGenderEnum genderEnum = UserGenderEnum.getByCode(gender);
        if(genderEnum == null){
            return;
        }
        String avatar = cos + genderEnum.getDefaultAvatar();
        this.update(Wrappers.lambdaUpdate(User.class)
                .eq(User::getId,user.getId())
                .set(User::getAvatar,avatar));
        UpdateUinfoReq uinfoReq = new UpdateUinfoReq();
        uinfoReq.setAccid(user.getId()+"");
        uinfoReq.setIcon(avatar);
        YxCommonR r = userRefClient.updateUinfo(uinfoReq);
        if(!r.isSuccess()){
            log.error("云信更新失败，需要检查！{}", JSON.toJSONString(r));
        }
    }

    @Override
    public void resetNickname(Long userId) {
        User user = this.getById(userId);
        if(user == null){
            return;
        }
        boolean update = this.update(Wrappers.lambdaUpdate(User.class)
                .eq(User::getId, user.getId())
                .set(User::getNickname, "用户" + user.getUsercode()));
        if(!update){
            return;
        }
        UpdateUinfoReq uinfoReq = new UpdateUinfoReq();
        uinfoReq.setAccid(user.getId()+"");
        uinfoReq.setName("用户"+user.getUsercode());
        YxCommonR r = userRefClient.updateUinfo(uinfoReq);
        if(!r.isSuccess()){
            log.error("云信更新失败，需要检查！{}", JSON.toJSONString(r));
        }
    }

    @Override
    public Page<UserAdminVo> pageAdmin(PageQuery pageQuery, UserAdminVo bo) {
        return baseMapper.pageAdmin(pageQuery.build(), bo);
    }


    @Override
    public Page<HomeUserListVo> homePage(HomePageReq params) {
        HomePageReq.VipQuery vipQuery = params.getVipQuery();
        boolean vip = false; // 是否为VIP
        boolean card = false; // 是否实名认证
        Long userId = LoginHelper.getUserId();
        if(userId != null){
            UserAuth userAuth = userAuthService.getByUserId(userId);
            card = userAuth != null && AuditEnum.SUCCESS.getCode().equals(userAuth.getCarAuth());
            User user = this.getById(userId);
            vip = user.getOpenVip();
        }
        if(vipQuery != null){
            if(StringUtils.isNotEmpty(vipQuery.getProfession()) ||
                vipQuery.getAnnualIncome() != null  || vipQuery.getZodiac() != null ||
                vipQuery.getSign() != null || vipQuery.getChildStatus() != null || vipQuery.getHousingStatus() != null  ||
                vipQuery.getCarStatus() != null || vipQuery.getAddressCode() != null){
                if(userId == null){
                    throw new ServiceException(ErrorEnum.VIP_AUTH);
                }
                if(!vip){
                    throw new ServiceException(ErrorEnum.VIP_AUTH);
                }
            }
        }
        Page<HomeUserListVo> page = baseMapper.homePageApp(params.build(), params);
        List<HomeUserListVo> records = page.getRecords();
        String cosDomain = systemConfigManager.getSystemConfig(SystemConfigEnum.COS_DOMAIN);
        for (HomeUserListVo record : records) {
            record.setBirthdayStr(BirthdayUtil.getMinBirthday(record.getBirthday()));
            boolean showAvatarBool = ShowAvatarUtil.showAvatar(vip, card, record.getShowAvatar());
            record.setShowAvatarBool(showAvatarBool);
            if(!record.getShowAvatarBool()){
                record.setAvatar(cosDomain + ImagesEnums.PRIVACY_IMAGE.getPath());
            }
        }
        return page;
    }

    @Override
    public List<HomeUserListVo> vipHomePage() {
        List<HomeUserListVo> result = baseMapper.vipHomePage(20);
        for (HomeUserListVo record : result) {
            record.setBirthdayStr(BirthdayUtil.getMinBirthday(record.getBirthday()));
        }
        return result;
    }

    @Override
    public boolean lock(Long id) {
        return this.update(Wrappers.lambdaUpdate(User.class).eq(User::getId,id).set(User::getStatus, 1));
    }

    @Override
    public boolean unlock(Long id) {
        return this.update(Wrappers.lambdaUpdate(User.class).eq(User::getId,id).set(User::getStatus, 0));
    }

    @Override
    public FullUserVo fullUserAdmin(Long userId) {
        FullUserVo vo = new FullUserVo();
        User user = this.getById(userId);
        vo.setUser(user);
        UserInfo userInfo = userInfoService.getByUserId(userId);
        vo.setUserInfo(userInfo);
        UserAuth userAuth = userAuthService.getByUserId(userId);
        vo.setUserAuth(userAuth);
        UserLogin userLogin = userLoginService.getByUserId(userId);
        vo.setUserLogin(userLogin);
        List<UserPictures> userPicturesList = userPicturesService.listByUserIdSuccess(userId);
        vo.setUserPicturesList(userPicturesList);
        UserExtend userExtend = userExtendService.getByUserId(userId);
        vo.setAccount(userExtend);
        return vo;
    }

    @Override
    public User getByMobile(String mobile){
        return this.getOne(Wrappers.lambdaQuery(User.class).eq(User::getMobile, mobile)
                .last("limit 1"));
    }

    @Autowired
    private LoginManager loginManager;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveUser(AddUserReq bo) {
        boolean mobile = PhoneUtil.isMobile(bo.getMobile());
        if(!mobile){
            throw new ServiceException("请填写正确的手机号格式");
        }
        User user = this.getByMobile(bo.getMobile());
        if(user != null){
            throw new ServiceException("手机号已存在!");
        }
        String lockKey = LockKey.getRegisterLockKey(bo.getMobile());
        RLock lock = redissonClient.getLock(lockKey);
        if(lock.isLocked()){
            throw new ServiceException("您点击太快了");
        }
        lock.lock();
        try {
            user = this.getByMobile(bo.getMobile());
            if(user != null){
                throw new ServiceException("手机号已存在!");
            }
            user = loginManager.registerUser(bo.getMobile(), null);
            UpdateUserReq updateUser = BeanConvertUtil.convertTo(bo, UpdateUserReq::new);
            updateUser.setId(user.getId());
            UserService userService = SpringUtil.getBean(UserService.class);
            userService.updateBaseUser(updateUser);
            if(StringUtils.isNotEmpty(bo.getPictures())){
                List<String> picturesList = Arrays.stream(bo.getPictures().split(",")).collect(Collectors.toList());
                userPicturesService.addPictures(picturesList,user);
            }
        }finally {
            lock.unlock();
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBaseUser(UpdateUserReq updateUserReq){
        User user = this.getById(updateUserReq.getId());
        if(user == null){
            throw new ServiceException("用户不存在!");
        }
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setType(updateUserReq.getType());
        updateUser.setNickname(updateUserReq.getNickname());
        updateUser.setAvatar(updateUserReq.getAvatar());
        updateUser.setGender(updateUserReq.getGender());
        updateUser.setHeight(updateUserReq.getHeight());
        updateUser.setWeight(updateUserReq.getWeight());
        updateUser.setForPersonals(updateUserReq.getForPersonals());
        if(updateUserReq.getBirthday() != null){
            updateUser.setAge(AgeUtil.getAge(updateUserReq.getBirthday()));
        }
        updateUser.setBirthday(updateUserReq.getBirthday());
        if(updateUserReq.getResidenceCode() != null){
            updateUser.setResidenceCode(updateUserReq.getResidenceCode());
            AreaCode areaCode = areaCodeService.getById(updateUserReq.getResidenceCode());
            updateUser.setResidenceCode(updateUserReq.getResidenceCode());
            updateUser.setResidenceName(areaCode.getFullname());
            updateUser.setResidenceCityCode(areaCode.getCityCode());
            updateUser.setResidenceCityName(areaCode.getCityName());
        }
        if(updateUserReq.getAddressCode() != null){
            AreaCode areaCode = areaCodeService.getById(updateUserReq.getAddressCode());
            updateUser.setAddressCode(updateUserReq.getAddressCode());
            updateUser.setAddressName(areaCode.getFullname());
        }
        updateUser.setEducation(updateUserReq.getEducation());
        updateUser.setMarriage(updateUserReq.getMarriage());
        updateUser.setProfession(updateUserReq.getProfession());
        updateUser.setAnnualIncome(updateUserReq.getAnnualIncome());
        this.updateById(updateUser);
        if(updateUserReq.getCarStatus() != null || updateUserReq.getHousingStatus() != null){
            userInfoService.update(Wrappers.lambdaUpdate(UserInfo.class)
                    .eq(UserInfo::getUserId, user.getId())
                    .set(updateUserReq.getCarStatus() != null,UserInfo::getCarStatus, updateUserReq.getCarStatus())
                    .set(updateUserReq.getHousingStatus() != null,UserInfo::getHousingStatus, updateUserReq.getHousingStatus()));
        }
        this.checkFinishStatus(user.getId());
    }

    @Override
    public void checkFinishStatus(Long userId){
        boolean finishBaseStatus = true;
        User user = this.getById(userId);
        if(user.getForPersonals() == null || user.getGender() == 0
                || user.getBirthday() == null || user.getHeight() == null
                || user.getWeight() == null || user.getResidenceCode() == null
                || user.getAddressCode() == null || user.getEducation() == null
                || user.getMarriage() == null || user.getProfession() == null
                || user.getAnnualIncome() == null || user.getUsercode() == null){
            finishBaseStatus = false;
        }
        UserInfo userInfo = userInfoService.getByUserId(userId);
        if(userInfo.getCarStatus() == null || userInfo.getHousingStatus() == null){
            finishBaseStatus = false;
        }
        if(finishBaseStatus){
            this.update(Wrappers.lambdaUpdate(User.class)
                    .eq(User::getId,user.getId())
                    .set(User::getBaseStep, 14)
                    .set(User::getFinishBaseStatus, 1));
        }
    }
}
