package com.ruoyi.system.user.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;

import javax.validation.Validator;

import com.ruoyi.bst.balanceLog.domain.BalanceLog;
import com.ruoyi.bst.balanceLog.domain.enums.BalanceLogBstType;
import com.ruoyi.bst.balanceLog.service.BalanceLogService;
import com.ruoyi.bst.changeRecord.domain.ChangeRecord;
import com.ruoyi.bst.changeRecord.domain.enums.ChangeRecordBstType;
import com.ruoyi.bst.changeRecord.mapper.ChangeRecordMapper;
import com.ruoyi.bst.lightingNum.domain.LightingNum;
import com.ruoyi.bst.lightingNum.domain.LightingNumVO;
import com.ruoyi.bst.lightingNum.mapper.LightingNumMapper;
import com.ruoyi.bst.order.domain.Order;
import com.ruoyi.bst.order.domain.OrderQuery;
import com.ruoyi.bst.userApp.service.UserAppService;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.user.domain.vo.UserConsumeVO;
import com.ruoyi.system.user.utils.UserUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import com.github.pagehelper.PageHelper;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.constants.ConfigKeys;
import com.ruoyi.common.core.domain.entity.Role;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.core.domain.vo.UserVO;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.system.config.service.ConfigService;
import com.ruoyi.system.dept.service.DeptService;
import com.ruoyi.system.post.domain.Post;
import com.ruoyi.system.post.mapper.PostMapper;
import com.ruoyi.system.role.mapper.RoleMapper;
import com.ruoyi.system.role.service.RoleService;
import com.ruoyi.system.user.domain.UserQuery;
import com.ruoyi.system.user.domain.vo.UserNameVO;
import com.ruoyi.system.user.mapper.UserMapper;
import com.ruoyi.system.user.service.UserService;
import com.ruoyi.system.user.service.UserValidator;
import com.ruoyi.system.userPost.domain.UserPost;
import com.ruoyi.system.userPost.mapper.UserPostMapper;
import com.ruoyi.system.userRole.domain.UserRole;
import com.ruoyi.system.userRole.mapper.UserRoleMapper;

/**
 * 用户 业务层处理
 *
 * @author ruoyi
 */
@Service
public class UserServiceImpl implements UserService
{

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PostMapper postMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private UserPostMapper userPostMapper;

    @Autowired
    private ConfigService configService;

    @Autowired
    private DeptService deptService;

    @Autowired
    protected Validator validator;

    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private UserValidator userValidator;

    @Autowired
    private RoleService roleService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private BalanceLogService balanceLogService;
    @Autowired
    private LightingNumMapper lightingNumMapper;
    @Autowired
    private ChangeRecordMapper changeRecordMapper;
    @Autowired
    private UserAppService userAppService;

    /**
     * 根据条件分页查询用户列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public List<UserVO> selectUserListScope(UserQuery user) {
        return userMapper.selectUserList(user);
    }

    /**
     * 根据条件分页查询已分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public List<UserVO> selectAllocatedList(User user)
    {
        return userMapper.selectAllocatedList(user);
    }

    /**
     * 根据条件分页查询未分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public List<UserVO> selectUnallocatedList(User user)
    {
        return userMapper.selectUnallocatedList(user);
    }

    /**
     * 通过用户名查询用户
     *
     * @param userName 用户名
     * @return 用户对象信息
     */
    @Override
    public UserVO selectUserByUserName(String userName)
    {
        return userMapper.selectUserByUserName(userName);
    }

    /**
     * 通过用户ID查询用户
     *
     * @param userId 用户ID
     * @return 用户对象信息
     */
    @Override
    public UserVO selectUserById(Long userId)
    {
        return userMapper.selectUserById(userId);
    }

    /**
     * 查询用户所属角色组
     *
     * @param userName 用户名
     * @return 结果
     */
    @Override
    public String selectUserRoleGroup(String userName)
    {
        List<Role> list = roleMapper.selectRolesByUserName(userName);
        if (CollectionUtils.isEmpty(list))
        {
            return StringUtils.EMPTY;
        }
        return list.stream().map(Role::getRoleName).collect(Collectors.joining(","));
    }

    /**
     * 查询用户所属岗位组
     *
     * @param userName 用户名
     * @return 结果
     */
    @Override
    public String selectUserPostGroup(String userName)
    {
        List<Post> list = postMapper.selectPostsByUserName(userName);
        if (CollectionUtils.isEmpty(list))
        {
            return StringUtils.EMPTY;
        }
        return list.stream().map(Post::getPostName).collect(Collectors.joining(","));
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param user 用户信息
     * @return
     */
    @Override
    public boolean checkPhoneUnique(User user)
    {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        User info = userMapper.checkPhoneUnique(user.getPhonenumber());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
        {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验email是否唯一
     *
     * @param user 用户信息
     * @return
     */
    @Override
    public boolean checkEmailUnique(User user)
    {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        User info = userMapper.checkEmailUnique(user.getEmail());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
        {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验用户是否允许操作
     *
     * @param user 用户信息
     */
    @Override
    public void checkUserAllowed(User user)
    {
        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin())
        {
            throw new ServiceException("不允许操作超级管理员用户");
        }
    }

    /**
     * 校验用户是否有数据权限
     *
     * @param userId 用户id
     */
    @Override
    public void checkUserDataScope(Long userId)
    {
        if (!User.isAdmin(SecurityUtils.getUserId()))
        {
            UserQuery user = new UserQuery();
            user.setUserId(userId);
            List<UserVO> users = this.selectUserListScope(user);
            if (StringUtils.isEmpty(users))
            {
                throw new ServiceException("没有权限访问用户数据！");
            }
        }
    }

    /**
     * 新增保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int insertUser(UserVO user)
    {
        // 校验
        ServiceUtil.assertion(StringUtils.isNotEmpty(user.getPhonenumber()) && !this.checkPhoneUnique(user),
                "新增用户'" + user.getUserName() + "'失败，手机号码已存在"
        );
        ServiceUtil.assertion(StringUtils.isNotEmpty(user.getEmail()) && !this.checkEmailUnique(user),
                "新增用户'" + user.getUserName() + "'失败，邮箱账号已存在"
        );

        // 填充数据
        if (user.getPassword() != null) {
            user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        }
        // 设置默认信息
        this.setDefaultInfo(user);

        // 操作数据库
        Integer result = transactionTemplate.execute(status -> {
            // 新增用户信息
            int rows = userMapper.insertUser(user);
            // 新增用户岗位关联
            insertUserPost(user);
            // 新增用户与角色管理
            insertUserRole(user);

            if (rows > 0) {
                // 后校验
                this.afterCheck(user.getUserId());

                this.clearCache();
            }

            return rows;
        });

        return result == null ? 0 : result;
    }

    private void setDefaultInfo(UserVO user) {
        if (StringUtils.isBlank(user.getWithdrawServiceType()) || user.getWithdrawServiceValue() == null) {
            String type = configService.selectConfigByKey(ConfigKeys.USER_DEFAULT_WITHDRAW_SERVICE_TYPE);
            BigDecimal value = configService.getDecimal(ConfigKeys.USER_DEFAULT_WITHDRAW_SERVICE_VALUE);
            if (type != null && value != null) {
                user.setWithdrawServiceType(type);
                user.setWithdrawServiceValue(value);
            }
        }
        if (user.getBonusDelay() == null) {
            user.setBonusDelay(24);
        }
    }

    void clearCache() {
        redisCache.deleteObject(CacheConstants.USER_NAME_LIST);
    }


    /**
     * 注册用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public boolean registerUser(UserVO user)
    {
        int rows = this.insertUser(user);

        if (rows > 0) {
            clearCache();
        }
        return rows > 0;
    }


    // 注册用户
    @Override
    public UserVO registerUser(String phone, String openId, Long appId) {
        if (StringUtils.isBlank(phone)) {
            return null;
        }

        // 生成昵称
        String nickName = null;
        if (StringUtils.hasText(openId)) {
            nickName = "微信" + openId.substring(openId.length() - 4);
        }
        if (StringUtils.hasText(phone)) {
            nickName = "用户" + phone.substring(phone.length() - 4);
        }

        UserVO user = new UserVO();
        user.setNickName(nickName);
        user.setPhonenumber(phone);
        user.setUserName(phone);
        user.setUserType(UserType.USER.getCode());
        user.setPassword(UserUtil.randomPassword());

        return transactionTemplate.execute(status -> {
            int rows = this.insertUser(user);

            if (rows > 0 ) {
                // 绑定APP
                if (appId != null && StringUtils.hasText(openId)) {
                    int bind = userAppService.bind(user.getUserId(), appId, openId);
                    ServiceUtil.assertion(bind != 1, "绑定APP失败");
                }
                // 返回用户信息
                return this.selectUserById(user.getUserId());
            }

            return null;
        });
    }


    /**
     * 修改保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int updateUser(UserVO user) {
        // 校验
        Long userId = user.getUserId();
        deptService.checkDeptDataScope(user.getDeptId());
        if (user.getRoleIds() != null) {
            roleService.checkRoleDataScope(user.getRoleIds());
        }
        ServiceUtil.assertion(StringUtils.isNotEmpty(user.getPhonenumber()) && !this.checkPhoneUnique(user),
                "修改用户'" + user.getUserName() + "'失败，手机号码已存在");
        ServiceUtil.assertion(StringUtils.isNotEmpty(user.getEmail()) && !this.checkEmailUnique(user),
                "修改用户'" + user.getUserName() + "'失败，邮箱账号已存在");

        Integer result = transactionTemplate.execute(status -> {
            // 删除用户与角色关联
            userRoleMapper.deleteUserRoleByUserId(userId);
            // 新增用户与角色管理
            insertUserRole(user);
            // 删除用户与岗位关联
            userPostMapper.deleteUserPostByUserId(userId);
            // 新增用户与岗位管理
            insertUserPost(user);
            int rows = userMapper.updateUser(user);

            if (rows > 0) {
                // 后校验
                this.afterCheck(user.getUserId());

                this.clearCache();
            }

            return rows;
        });

        return result == null ? 0 : result;
    }

    void afterCheck(Long userId) {
        UserVO vo = selectUserById(userId);
        userValidator.validate(vo);
    }

    /**
     * 用户授权角色
     *
     * @param userId 用户ID
     * @param roleIds 角色组
     */
    @Override
    @Transactional
    public void insertUserAuth(Long userId, Long[] roleIds)
    {
        userRoleMapper.deleteUserRoleByUserId(userId);
        insertUserRole(userId, roleIds);
    }

    /**
     * 修改用户状态
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int updateUserStatus(User user)
    {
        int rows = userMapper.updateUser(user);

        if (rows > 0) {
            clearCache();
        }

        return rows;
    }

    /**
     * 修改用户基本信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int updateUserProfile(User user)
    {
        int rows = userMapper.updateUser(user);

        if (rows > 0) {
            clearCache();
        }

        return rows;
    }

    /**
     * 修改用户头像
     *
     * @param userName 用户名
     * @param avatar 头像地址
     * @return 结果
     */
    @Override
    public boolean updateUserAvatar(String userName, String avatar)
    {
        int rows = userMapper.updateUserAvatar(userName, avatar);

        if (rows > 0) {
            clearCache();
        }

        return rows > 0;
    }

    /**
     * 重置用户密码
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int resetPwd(User user)
    {
        return userMapper.updateUser(user);
    }

    /**
     * 重置用户密码
     *
     * @param userName 用户名
     * @param password 密码
     * @return 结果
     */
    @Override
    public int resetUserPwd(String userName, String password)
    {
        return userMapper.resetUserPwd(userName, password);
    }

    /**
     * 新增用户角色信息
     *
     * @param user 用户对象
     */
    public void insertUserRole(UserVO user)
    {
        this.insertUserRole(user.getUserId(), user.getRoleIds());
    }

    /**
     * 新增用户岗位信息
     *
     * @param user 用户对象
     */
    public void insertUserPost(UserVO user)
    {
        Long[] posts = user.getPostIds();
        if (StringUtils.isNotEmpty(posts))
        {
            // 新增用户与岗位管理
            List<UserPost> list = new ArrayList<UserPost>(posts.length);
            for (Long postId : posts)
            {
                UserPost up = new UserPost();
                up.setUserId(user.getUserId());
                up.setPostId(postId);
                list.add(up);
            }
            userPostMapper.batchUserPost(list);
        }
    }

    /**
     * 新增用户角色信息
     *
     * @param userId 用户ID
     * @param roleIds 角色组
     */
    public void insertUserRole(Long userId, Long[] roleIds)
    {
        if (userId == null) {
            return;
        }
        if (StringUtils.isNotEmpty(roleIds))
        {
            // 新增用户与角色管理
            List<UserRole> list = new ArrayList<UserRole>(roleIds.length);
            for (Long roleId : roleIds)
            {
                if (roleId == null) {
                    continue;
                }
                UserRole ur = new UserRole();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
                list.add(ur);
            }
            if (CollectionUtils.isNotEmptyElement(list)) {
                userRoleMapper.batchUserRole(list);
            }
        }
    }

    /**
     * 通过用户ID删除用户
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteUserById(Long userId)
    {
        // 删除用户与角色关联
        userRoleMapper.deleteUserRoleByUserId(userId);
        // 删除用户与岗位表
        userPostMapper.deleteUserPostByUserId(userId);
        int rows = userMapper.deleteUserById(userId);

        if (rows > 0) {
            clearCache();
        }

        return rows;
    }

    /**
     * 批量删除用户信息
     *
     * @param userIds 需要删除的用户ID
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteUserByIds(Long[] userIds)
    {
        for (Long userId : userIds)
        {
            checkUserAllowed(new User(userId));
            checkUserDataScope(userId);
        }
        // 删除用户与角色关联
        userRoleMapper.deleteUserRole(userIds);
        // 删除用户与岗位关联
        userPostMapper.deleteUserPost(userIds);
        int rows = userMapper.deleteUserByIds(userIds);

        if (rows > 0) {
            clearCache();
        }

        return rows;
    }

    @Override
    public UserVO selectUserByPhonenumber(String phonenumber) {
        if (StringUtils.isBlank(phonenumber)) {
            return null;
        }
        UserQuery query = new UserQuery();
        query.setEqPhonenumber(phonenumber);
        return this.selectOne(query);
    }

    @Override
    public List<UserVO> selectUserList(UserQuery query) {
        return userMapper.selectUserList(query);
    }

    @Override
    public List<UserNameVO> selectAllUserNameList() {
        List<UserNameVO> list = redisCache.getCacheObject(CacheConstants.USER_NAME_LIST);
        if (CollectionUtils.isEmptyElement(list)) {
            UserQuery query = new UserQuery();
            query.setExcludeUserId(1L);
            list = userMapper.selectNameList(query);
            if (CollectionUtils.isNotEmptyElement(list)) {
                redisCache.setCacheObject(CacheConstants.USER_NAME_LIST, list);
            }
        }
        return list;
    }

    @Override
    public List<UserVO> selectByIds(List<Long> ids) {
        if (CollectionUtils.isEmptyElement(ids)) {
            return Collections.emptyList();
        }
        UserQuery query = new UserQuery();
        query.setUserIds(ids);
        return userMapper.selectUserList(query);
    }

    private UserVO selectOne(UserQuery query) {
        PageHelper.startPage(1, 1);
        List<UserVO> list = userMapper.selectUserList(query);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public List<UserVO> selectUserListByNickNames(List<String> nickNames) {
        if (CollectionUtils.isEmptyElement(nickNames)) {
            return Collections.emptyList();
        }

        UserQuery query = new UserQuery();
        query.setNickNames(nickNames);
        return userMapper.selectUserList(query);
    }

    @Override
    public List<Long> selectUserIdsByDeptIds(List<Long> deptIds) {
        if (CollectionUtils.isEmptyElement(deptIds)) {
            return Collections.emptyList();
        }
        UserQuery query = new UserQuery();
        query.setDeptIds(deptIds);
        return userMapper.selectUserIds(query);
    }

    @Override
    public UserVO selectByAppOpenId(Long appId, String openId) {
        if (appId == null || StringUtils.isBlank(openId)) {
            return null;
        }
        UserQuery query = new UserQuery();
        query.setAppId(appId);
        query.setEqOpenId(openId);
        return this.selectOne(query);
    }

    @Override
    public int addLightingNum(Order order) {
        Long userId = order.getUserId();
        Integer number = order.getSuitNum();
        Long storeId = order.getStoreId();
        Long orderId = order.getId();
        return addLightingNum(userId, storeId, number, ChangeRecordBstType.RECHARGE.getCode(),orderId,"用户充值,订单次数增加"+number);
    }


    public int addLightingNum(Long userId, Long storeId, Integer number ,String bstType ,Long bstId ,String reason) {
        if (userId == null || number == null || storeId == null) {
            return 0;
        }
        // 如果次数为0，则不进行任何操作
        if (number == 0) {
            return 1;
        }
        // 如果爆灯次数为负数，则抛出异常
        ServiceUtil.assertion(number < 0, "增加的次数不能为负数");

        Integer result = transactionTemplate.execute(status -> {
            // 查询用户爆灯次数，并锁定
            Integer lightingNumber = lightingNumMapper.selectLightingNumberForUpdate(userId,storeId);
            if (lightingNumber == null) {
                lightingNumber = 0;
            }

            // 更新用户爆灯次数
            LightingNumVO vo = lightingNumMapper.selectLightingNumByUserId(userId, storeId);
            int rows = 0;
            // 第一次插入，新建一条爆灯次数记录
            if (vo == null) {
                LightingNum lightingNum = new LightingNum();
                lightingNum.setUserId(userId);
                lightingNum.setStoreId(storeId);
                lightingNum.setNumber(number);
                lightingNum.setCreateTime(DateUtils.getNowDate());
                rows = lightingNumMapper.insertLightingNum(lightingNum);
            }
            // 更新用户爆灯次数
            else {
                rows = lightingNumMapper.addLightingNum(userId, storeId,number);
            }
            // 新增爆灯次数变化
            if (rows > 0) {
                ChangeRecord record = new ChangeRecord();
                record.setUserId(userId);
                record.setStoreId(storeId);
                record.setNumber(number);
                record.setBeforeNum(lightingNumber);
                record.setAfterNum(lightingNumber+number);
                record.setBstId(bstId);
                record.setReason(reason);
                record.setBstType(bstType);
                record.setCreateTime(DateUtils.getNowDate());
                int recordInsert = changeRecordMapper.insertChangeRecord(record);
                ServiceUtil.assertion(recordInsert != 1, "新增爆灯次数记录失败");
            }
            return rows;
        });
        return result == null ? 0 : result;
    }

    @Override
    public int subtractBalance(Long userId, BigDecimal amount, BalanceLogBstType bstType, Long bstId, String reason, boolean checkBalance) {
        if (userId == null || amount == null) {
            return 0;
        }
        // 如果金额为0，则不进行任何操作
        if (amount.compareTo(BigDecimal.ZERO) == 0) {
            return 1;
        }
        // 如果金额为负数，则抛出异常
        ServiceUtil.assertion(amount.compareTo(BigDecimal.ZERO) < 0, "减少的金额不能为负数");

        Integer result = transactionTemplate.execute(status -> {
            // 查询用户余额，并锁定
            BigDecimal balance = userMapper.selectBalanceForUpdate(userId);
            if (balance == null) {
                balance = BigDecimal.ZERO;
            }

            // 更新用户余额
            int rows = userMapper.subtractBalance(userId, amount, checkBalance);

            // 新增余额日志
            if (rows > 0) {
                BalanceLog log = new BalanceLog();
                log.setUserId(userId);
                log.setAmount(amount.negate());
                log.setBeforeBalance(balance);
                log.setAfterBalance(balance.subtract(amount));
                log.setBstType(bstType.getCode());
                log.setBstId(bstId);
                log.setReason(reason);
                int logInsert = balanceLogService.insertBalanceLog(log);
                ServiceUtil.assertion(logInsert != 1, "新增余额日志失败");
            }

            return rows;
        });

        return result == null ? 0 : result;
    }

    @Override
    public int updateAreaId(Long userId, Long areaId) {
        if (userId == null || areaId == null) {
            return 0;
        }
        User user = new User();
        user.setUserId(userId);
        user.setAreaId(areaId);
        return userMapper.updateUser(user);
    }

    @Override
    public UserVO selectSimpleById(Long userId) {
        return userMapper.selectSimpleById(userId);
    }

    @Override
    public List<UserConsumeVO> selectUserIdsByStoreId(OrderQuery query) {
        return userMapper.selectUserIdsByStoreId(query);
    }

    @Override
    public int updateUserBasicInfo(UserVO vo) {
        return userMapper.updateUser(vo);
    }
}
