package com.mmc.iuav.user.service.impl;

import com.mmc.iuav.general.CodeUtil;
import com.mmc.iuav.page.PageResult;
import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.response.ResultEnum;
import com.mmc.iuav.user.controller.userpoints.config.NumberOfUserPoints;
import com.mmc.iuav.user.controller.userpoints.config.UserPointsEnum;
import com.mmc.iuav.user.dao.*;
import com.mmc.iuav.user.dao.userpoints.UserPointsDao;
import com.mmc.iuav.user.dao.userpoints.UserPointsDetailsDao;
import com.mmc.iuav.user.dao.xzsz.XzDao;
import com.mmc.iuav.user.entity.*;
import com.mmc.iuav.user.entity.userpoints.UserPointsDO;
import com.mmc.iuav.user.entity.userpoints.UserPointsDetails;
import com.mmc.iuav.user.model.dto.LoginSuccessDTO;
import com.mmc.iuav.user.model.dto.RealNameAuthDTO;
import com.mmc.iuav.user.model.dto.UserAccountSimpleDTO;
import com.mmc.iuav.user.model.qo.UserAccountQO;
import com.mmc.iuav.user.model.qo.UserMessageQO;
import com.mmc.iuav.user.model.qo.UserRcdQO;
import com.mmc.iuav.user.model.vo.CompanyAuthVO;
import com.mmc.iuav.user.model.vo.CooperationTagVO;
import com.mmc.iuav.user.model.vo.TopInviteVO;
import com.mmc.iuav.user.model.vo.UserAccountVO;
import com.mmc.iuav.user.model.vo.userpoints.UserPointsVO;
import com.mmc.iuav.user.mq.MqProducer;
import com.mmc.iuav.user.service.CompanyAuthService;
import com.mmc.iuav.user.service.RealNameAuthService;
import com.mmc.iuav.user.service.UserAccountService;
import com.mmc.iuav.user.service.WxService;
import com.mmc.iuav.user.util.SmsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author: zj
 * @Date: 2023/5/16 13:48
 */
@Slf4j
@Service
public class UserAccountServiceImpl implements UserAccountService {

    @Autowired
    private UserServiceDao userServiceDao;

    @Autowired
    private CompanyAuthService companyAuthService;

    @Autowired
    private RealNameAuthService realNameAuthService;

    @Autowired
    private CooperationDao cooperationDao;

    @Autowired
    private WxService wxService;

    @Autowired
    private MqProducer mqProducer;

    @Autowired
    private UserPointsDao userPointsDao;

    @Autowired
    private UserPointsDetailsDao userPointsDetailsDao;

    @Autowired
    private RealNameAuthDao realNameAuthDao;

    @Autowired
    private XzDao xzDao;

    @Autowired
    private UserSubInfoDao userSubInfoDao;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Override
    public UserAccountVO getUserAccountInfoByUnionId(String unionId) {
        UserAccountDO userAccountDO = userServiceDao.getUserAccountInfoByUnionId(unionId);
        if (userAccountDO != null) {
            return userAccountDO.buildUserAccountVO();
        }
        return null;
    }

    @Override
    public void insertUserAccount(UserAccountDO userAccountDO) {
        userServiceDao.insertUserAccount(userAccountDO);
    }

    @Override
    public UserAccountVO getUserAccountById(Integer userAccountId) {
        UserAccountDO userAccountDO = userServiceDao.getUserAccountById(userAccountId);
        if (userAccountDO == null) {
            return null;
        }
        String districtChild = userServiceDao.getDistrictChild(userAccountDO.getDistrictChildId());
        userAccountDO.setRegion(districtChild);
        UserAccountVO userAccountVO = userAccountDO.buildUserAccountVO();
        ResultBody<RealNameAuthDTO> nameAuthDTOResultBody = realNameAuthService.userDetail(userAccountId);
        RealNameAuthDTO realNameAuthDTO = nameAuthDTOResultBody.getResult();
        if (realNameAuthDTO != null && realNameAuthDTO.getCheckStatus().equals(1)) {
            userAccountVO.setRealNameAuthStatus(1);
            userAccountVO.setUserName(realNameAuthDTO.getUserName());
        }
        CompanyAuthVO companyAuthVO = companyAuthService.getCompanyAuthByUId(userAccountId);
        if (companyAuthVO != null) {
            userAccountVO.setCompanyAuthStatus(companyAuthVO.getAuthStatus());
        } else {
            userAccountVO.setCompanyAuthStatus(0);
        }
        List<CooperationTagDO> cooperationTagDOS = cooperationDao.listUserCooperationTag(userAccountId);
        if (!CollectionUtils.isEmpty(cooperationTagDOS)) {
            List<CooperationTagVO> cooperationTags = cooperationTagDOS.stream().map(CooperationTagDO::buildCooperationTagVO).collect(Collectors.toList());
            userAccountVO.setCooperationTagVOS(cooperationTags);
        }
        XzAuthDO xzAuthDO = xzDao.getXzAuthByUserAccountId(userAccountId);
        if (xzAuthDO != null) {
            userAccountVO.setXzAuthStatus(xzAuthDO.getXzAuthStatus());
        } else {
            userAccountVO.setXzAuthStatus(0);
        }
        UserSubInfoDO userSubInfoDO = userSubInfoDao.getUserSubInfoByUnionId(userAccountDO.getUnionId());
        if (userSubInfoDO != null && userSubInfoDO.getRegStatus().equals(1)) {
            userAccountVO.setSubStatus(1);
        } else {
            userAccountVO.setSubStatus(0);
        }
        return userAccountVO;
    }

    @Override
    public ResultBody update(UserAccountVO userAccountVO) {
        UserAccountDO userAccountDO = new UserAccountDO(userAccountVO);
        int i = userServiceDao.selectUserAccountNickName(userAccountDO);
        if (i!=0){
            return ResultBody.error("昵称被占用，请重新修改");
        }
        userServiceDao.update(userAccountDO);
        mqProducer.sentUserInfoChangedMsg(userAccountVO);
        return ResultBody.success();
    }

    @Override
    public UserAccountSimpleDTO getUserSimpleInfo(Integer userAccountId) {
        UserAccountDO userAccountDO = userServiceDao.getUserAccountById(userAccountId);
        if (userAccountDO == null) {
            return null;
        }
        String districtChild = userServiceDao.getDistrictChild(userAccountDO.getDistrictChildId());
        userAccountDO.setRegion(districtChild);
        UserAccountSimpleDTO userAccountSimpleDTO = userAccountDO.buildUserAccountSimpleDTO();
        CompanyAuthVO companyAuthVO = companyAuthService.getCompanyAuthByUId(userAccountId);
        if (companyAuthVO != null) {
            userAccountSimpleDTO.setCompanyAuthStatus(companyAuthVO.getAuthStatus());
        } else {
            userAccountSimpleDTO.setCompanyAuthStatus(0);
        }
        List<CooperationTagDO> cooperationTagDOS = cooperationDao.listUserCooperationTag(userAccountId);
        if (!CollectionUtils.isEmpty(cooperationTagDOS)) {
            List<CooperationTagVO> cooperationTags = cooperationTagDOS.stream().map(CooperationTagDO::buildCooperationTagVO).collect(Collectors.toList());
            userAccountSimpleDTO.setCooperationTagVOS(cooperationTags);
        }
        ResultBody<RealNameAuthDTO> userDetail = realNameAuthService.userDetail(userAccountId);
        if (userDetail.getCode().equals(ResultEnum.SUCCESS.getResultCode()) && userDetail.getResult() != null) {
            userAccountSimpleDTO.setUserName(userDetail.getResult().getUserName());
        }
        return userAccountSimpleDTO;
    }

    @Override
    public List<Integer> feignListUserAccountIds(Integer provinceCode, Integer cityCode, Integer districtCode) {
        List<Integer> ids = userServiceDao.listUserAccountIdsByDistrictCode(provinceCode, cityCode, districtCode);
        return ids;
    }

    @Override
    public List<UserAccountSimpleDTO> feignListUserAccount(UserAccountQO userAccountQO) {
        List<UserAccountDO> list = userServiceDao.feignListUserAccount(userAccountQO);
        if (list == null) {
            return null;
        }
        for (UserAccountDO userAccountDO : list) {
            Integer districtChildId = userAccountDO.getDistrictChildId();
            if (districtChildId!=null){
                String districtChild = userServiceDao.getDistrictChild(districtChildId);
                userAccountDO.setRegion(districtChild);
            }
        }
        List<UserAccountSimpleDTO> accountSimpleDTOS = list.stream().map(UserAccountDO::buildUserAccountSimpleDTO).collect(Collectors.toList());
        //设置用户的渠道等级
        buildCooperationTagVO(accountSimpleDTOS);
        return accountSimpleDTOS;
    }

    public void buildCooperationTagVO(List<UserAccountSimpleDTO> accountSimpleDTOS) {
        List<Integer> uIds = accountSimpleDTOS.stream().map(UserAccountSimpleDTO::getId).collect(Collectors.toList());
        //设置用户的渠道等级
        List<CooperationTagDO> cooperationTagDOS = cooperationDao.listUserCooperationTagByUIds(uIds);
        if (!CollectionUtils.isEmpty(cooperationTagDOS)) {
            Map<Integer, List<CooperationTagDO>> userTagsMap = cooperationTagDOS.stream().collect(Collectors.groupingBy(CooperationTagDO::getUserAccountId));
            for (UserAccountSimpleDTO simpleDTO : accountSimpleDTOS) {
                List<CooperationTagDO> tagDOS = userTagsMap.get(simpleDTO.getId());
                if (!CollectionUtils.isEmpty(tagDOS)) {
                    List<CooperationTagVO> cooperationTagVOS = tagDOS.stream().map(CooperationTagDO::buildCooperationTagVO).collect(Collectors.toList());
                    simpleDTO.setCooperationTagVOS(cooperationTagVOS);
                }
            }
        }
    }

    @Transactional
    @Override
    public ResultBody getUserPhoneNumber(Integer id, String code, Integer rcdUserId) {
        UserAccountDO userAccountDO = userServiceDao.getUserAccountById(id);
        if (userAccountDO.getPhoneNum() != null) {
            return ResultBody.success();
        }
        String userPhoneNumber = wxService.getUserPhoneNumber(id, code);
        log.info("授权手机号，用户：{}，手机号：{}", id, userPhoneNumber);
        if (StringUtils.isBlank(userPhoneNumber)) {
            return ResultBody.error(ResultEnum.AUTH_PHONE_NUMBER_ERROR);
        }
        UserAccountDO userAccount = new UserAccountDO();
        userAccount.setId(id);
        userAccount.setPhoneNum(userPhoneNumber);
        userServiceDao.update(userAccount);
        if (rcdUserId != null) {
            UserRcdDO userRcd = new UserRcdDO();
            userRcd.setUserAccountId(id);
            userRcd.setRcdUserId(rcdUserId);
            userServiceDao.insertUserRcd(userRcd);
        }

        /**
         * 积分
         */
        extracted(id);
        RealNameAuthDO realNameAuthByUId = realNameAuthDao.getRealNameAuthByUId(id);
        if (realNameAuthByUId != null && realNameAuthByUId.getCheckStatus() == 1) {
            realNameextracted(id);
        }
        return ResultBody.success();
    }

    private void extracted(Integer id) {
        UserPointsVO userPointsVO = new UserPointsVO(id, NumberOfUserPoints.match(0).getMessage());
        //积分
        UserPointsDO pointsDO = userPointsDao.selectUserPoints(userPointsVO.getUserAccountId());
        UserPointsDO points = null;
        if (pointsDO != null) {
            Integer totalPoints = userPointsVO.getTotalPoints();
            Integer totalPoints1 = pointsDO.getTotalPoints();
            totalPoints += totalPoints1;
            userPointsVO.setTotalPoints(totalPoints);
            points = new UserPointsDO(userPointsVO);
            userPointsDao.updatePoints(points);
        } else if (pointsDO == null) {
            points = new UserPointsDO(userPointsVO);
            userPointsDao.insertPoints(points);
        }
        UserPointsDetails userPointsDetails = new UserPointsDetails(id, NumberOfUserPoints.match(0).getMessage(), UserPointsEnum.match(0).getMessage());
        userPointsDetailsDao.insertPointsDetails(userPointsDetails);
    }

    private void realNameextracted(Integer id) {
        UserPointsVO userPointsVO = new UserPointsVO(id, NumberOfUserPoints.match(1).getMessage());
        //积分
        UserPointsDO pointsDO = userPointsDao.selectUserPoints(userPointsVO.getUserAccountId());
        UserPointsDO points = null;
        if (pointsDO != null) {
            Integer totalPoints = userPointsVO.getTotalPoints();
            Integer totalPoints1 = pointsDO.getTotalPoints();
            totalPoints += totalPoints1;
            userPointsVO.setTotalPoints(totalPoints);
            points = new UserPointsDO(userPointsVO);
            userPointsDao.updatePoints(points);
        } else if (pointsDO == null) {
            points = new UserPointsDO(userPointsVO);
            userPointsDao.insertPoints(points);
        }
        UserPointsDetails userPointsDetails = new UserPointsDetails(id, NumberOfUserPoints.match(1).getMessage(), UserPointsEnum.match(1).getMessage());
        userPointsDetailsDao.insertPointsDetails(userPointsDetails);
    }

    @Override
    public List<UserAccountSimpleDTO> feignListUserAccountByIds(List<Integer> ids) {
        List<UserAccountDO> userAccountDOS = userServiceDao.listUserAccountByIds(ids);
        if (!CollectionUtils.isEmpty(userAccountDOS)) {
            List<UserAccountSimpleDTO> userAccountSimpleDTOS = userAccountDOS.stream().map(UserAccountDO::buildUserAccountSimpleDTO).collect(Collectors.toList());
            //设置用户的渠道等级
            buildCooperationTagVO(userAccountSimpleDTOS);
            return userAccountSimpleDTOS;
        }
        return null;
    }

    @Override
    public List<UserAccountSimpleDTO> feignListRcdUserInfo(List<Integer> userIds) {
        List<UserAccountDO> userAccountDOS = userServiceDao.feignListRcdUserInfo(userIds);
        if (!CollectionUtils.isEmpty(userAccountDOS)) {
            List<UserAccountSimpleDTO> userAccountSimpleDTOS = userAccountDOS.stream().map(UserAccountDO::buildUserAccountSimpleDTO).collect(Collectors.toList());
            //设置用户的渠道等级
            buildCooperationTagVO(userAccountSimpleDTOS);
            return userAccountSimpleDTOS;
        }
        return null;
    }

    @Override
    public Integer feignGetSuperiorRef(Integer userAccountId) {
        UserRcdDO userRcdDO = userServiceDao.getUserRcdDO(userAccountId);
        if (userRcdDO != null) {
            return userRcdDO.getId();
        }
        return null;
    }

    @Override
    public UserAccountSimpleDTO feignGetUserRcdInfo(Integer userAccountId) {
        UserAccountDO rcdAccountDO = userServiceDao.getUserRcdByAccountId(userAccountId);
        if (rcdAccountDO != null) {
            List<CooperationTagDO> cooperationTagDOS = cooperationDao.listUserCooperationTag(userAccountId);
            UserAccountSimpleDTO userAccountSimpleDTO = rcdAccountDO.buildUserAccountSimpleDTO();
            if (!CollectionUtils.isEmpty(cooperationTagDOS)) {
                List<CooperationTagVO> cooperationTagVOS = cooperationTagDOS.stream().map(CooperationTagDO::buildCooperationTagVO).collect(Collectors.toList());
                userAccountSimpleDTO.setCooperationTagVOS(cooperationTagVOS);
            }
            return userAccountSimpleDTO;
        }
        return null;
    }

    @Override
    public ResultBody listAppUser(UserAccountQO param, LoginSuccessDTO loginSuccessDTO) {
        if (loginSuccessDTO.getRoleInfo() != null && !loginSuccessDTO.getRoleInfo().getSuperAdmin().equals(1)) {
            param.setCompanyInfoId(loginSuccessDTO.getCompanyInfoVO().getId());
        }
        int count = userServiceDao.countListAppUser(param);
        if (count == 0) {
            return ResultBody.success(PageResult.buildPage(param.getPageNo(), param.getPageSize(), count));
        }
        int pageNo = param.getPageNo();
        param.buildCurrentPage();
        List<UserAccountDO> userAccountDOList = userServiceDao.listAppUser(param);
        List<Integer> uIds = userAccountDOList.stream().map(UserAccountDO::getId).collect(Collectors.toList());
        // 设置加盟商标签
        buildTagsInfo(uIds, userAccountDOList);
        // 设置推荐（邀请）伙伴个数
        buildInviteCount(uIds, userAccountDOList);
        List<UserAccountVO> userAccountVOS = userAccountDOList.stream().map(UserAccountDO::buildUserAccountVO).collect(Collectors.toList());
        return ResultBody.success(PageResult.buildPage(pageNo, param.getPageSize(), count, userAccountVOS));
    }

    /**
     * 设置推荐伙伴个数
     *
     * @param uIds
     * @param userAccountDOList
     */
    private void buildInviteCount(List<Integer> uIds, List<UserAccountDO> userAccountDOList) {
        List<UserAccountDO> userInviteList = userServiceDao.getInviteCount(uIds);
        if (CollectionUtils.isEmpty(userInviteList)) {
            userInviteList.forEach(d -> d.setInviteCount(0));
        } else {
            Map<Integer, Integer> inviteCount = userInviteList.stream().collect(Collectors.toMap(UserAccountDO::getId, UserAccountDO::getInviteCount));
            userAccountDOList.forEach(d -> d.setInviteCount(inviteCount.get(d.getId()) == null ? 0 : inviteCount.get(d.getId())));
        }
    }

    /**
     * 设置加盟商标签
     *
     * @param uIds
     * @param userAccountDOList
     */
    private void buildTagsInfo(List<Integer> uIds, List<UserAccountDO> userAccountDOList) {
        List<CooperationTagDO> cooperationTagDOS = cooperationDao.listUserCooperationTagByUIds(uIds);
        Map<Integer, List<CooperationTagDO>> userTagsMap = cooperationTagDOS.stream().collect(Collectors.groupingBy(CooperationTagDO::getUserAccountId));
        for (UserAccountDO userAccountDO : userAccountDOList) {
            List<CooperationTagDO> userCooperationTagDOS = userTagsMap.get(userAccountDO.getId());
            if (!CollectionUtils.isEmpty(userCooperationTagDOS)) {
                userAccountDO.setCooperationTagDOS(userCooperationTagDOS);
            }
        }
    }

    @Autowired
    private CompanyDao companyDao;

    @Transactional
    @Override
    public ResultBody disableAppAccount(Integer userAccountId) {
        UserAccountVO userAccountVO = new UserAccountVO();
        userAccountVO.setId(userAccountId);
        userAccountVO.setDeleted(1);
        // 删除绑定企业信息，
        // 该企业只有一人时可以直接删除，或者不是管理员时也可以直接删除，
        // 是管理者时并且有多人则不能删除，提醒解绑成员后才能删除
        CompanyInfoDO companyInfoDO = companyDao.getAppCompanyInfoUId(userAccountId);
        if (companyInfoDO != null) {
            int members = companyDao.countCompanyMembers(companyInfoDO.getId());
            if (members > 1 && companyInfoDO.getLeader().equals(1)) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResultBody.error("该用户是单位管理员，暂时不能删除");
            }
            companyDao.unbindCompanyMember(userAccountId, companyInfoDO.getId());
        }
        userServiceDao.disableUserAccount(CodeUtil.removeUserAccount(), userAccountId);
        mqProducer.sentUserInfoChangedMsg(userAccountVO);
        return ResultBody.success();
    }

    @Override
    public ResultBody countRcd(Integer userAccountId) {
        Integer count = userServiceDao.countRcd(userAccountId);
        return ResultBody.success(count);
    }

    @Override
    public ResultBody listUserRcd(UserRcdQO userRcdQO) {
        int count = userServiceDao.countRcd(userRcdQO.getUserAccountId());
        if (count == 0) {
            return ResultBody.success(PageResult.buildPage(userRcdQO.getPageNo(), userRcdQO.getPageSize(), count));
        }
        int pageNo = userRcdQO.getPageNo();
        userRcdQO.buildCurrentPage();
        List<UserAccountDO> userRcd = userServiceDao.listUserRcd(userRcdQO);
        List<UserAccountVO> userAccountVOS = userRcd.stream().map(UserAccountDO::buildUserAccountVO).collect(Collectors.toList());
        return ResultBody.success(PageResult.buildPage(pageNo, userRcdQO.getPageSize(), count, userAccountVOS));
    }

    @Override
    public ResultBody topRcd(Integer topNum) {
        List<UserAccountDO> topInviteUser = userServiceDao.topRcd(topNum);
        if (!CollectionUtils.isEmpty(topInviteUser)) {
            List<TopInviteVO> topInviteVOS = topInviteUser.stream().map(UserAccountDO::buildTopInviteVO).collect(Collectors.toList());
            return ResultBody.success(topInviteVOS);
        }
        return ResultBody.success();
    }

    @Override
    public ResultBody getUserAccountByPhoneNum(String phoneNum) {
        List<UserAccountDO> userAccountDOS = userServiceDao.getUserAccountByPhoneNum(phoneNum);
        if (!CollectionUtils.isEmpty(userAccountDOS)) {
            return ResultBody.success(userAccountDOS.stream().map(UserAccountDO::buildUserAccountVO).collect(Collectors.toList()));
        }
        return ResultBody.success();
    }

    @Override
    public ResultBody getVerifyCode(Integer userAccountId, String phoneNum) {
        Integer count= userServiceDao.countPhoneNum(phoneNum);
        if(count>0){
            return ResultBody.error("80001","手机号已存在");
        }
       // 根据手机号生成验证码
        String verifyCode = CodeUtil.getRandomNum(6);
        // 保存到redis中
        Map<String, String> redisData = new HashMap<>();
        redisData.put("userAccountId", userAccountId + "");
        redisData.put("phoneNum", phoneNum);
        redisData.put("verifyCode", verifyCode);
        stringRedisTemplate.opsForHash().putAll(verifyCode + userAccountId, redisData);
        stringRedisTemplate.expire(verifyCode + userAccountId, 60, TimeUnit.SECONDS);
        // 发送给用户
        SmsUtil.verifyCode(verifyCode, phoneNum);
        return ResultBody.success();
    }

    @Override
    public ResultBody updatePhoneNum(Integer userAccountId, String verifyCode) {
        Map<Object, Object> redisData = stringRedisTemplate.opsForHash().entries(verifyCode + userAccountId);
        if (redisData.isEmpty()) {
            return ResultBody.error("验证码错误,请重新输入");
        }
        String code = redisData.get("verifyCode").toString();
        String phoneNum = redisData.get("phoneNum").toString();
        // 验证码错误则修改失败，并提醒
        if (!code.equals(verifyCode)) {
            return ResultBody.error("验证码错误,请重新输入");
        }
        int count = userServiceDao.countPhoneNums(phoneNum, userAccountId);
        if (count > 0) {
            return ResultBody.error("80001","手机号已存在");
        }
        userServiceDao.updateAccountPhone(userAccountId, phoneNum);
        return ResultBody.success();
    }

    @Override
    public ResultBody appUpdateUser(UserMessageQO userMessageQO) {
        int i = userServiceDao.selectUserAccount(userMessageQO);
        if (i!=0){
            return ResultBody.error("昵称被占用，请重新修改");
        }else{
            userServiceDao.appUpdateUser(userMessageQO);
        }
        return ResultBody.success();
    }


}
