package com.starry.admin.modules.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
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.github.yulichang.wrapper.MPJLambdaWrapper;
import com.starry.admin.manager.AsyncManager;
import com.starry.admin.manager.factory.AsyncFactory;
import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity;
import com.starry.admin.modules.clerk.service.IPlayClerkUserInfoService;
import com.starry.admin.modules.personnel.module.entity.PlayPersonnelAdminInfoEntity;
import com.starry.admin.modules.personnel.module.entity.PlayPersonnelGroupInfoEntity;
import com.starry.admin.modules.personnel.module.entity.PlayPersonnelWaiterInfoEntity;
import com.starry.admin.modules.personnel.module.vo.PlayPersonnelUserInfoQueryVo;
import com.starry.admin.modules.personnel.module.vo.PlayPersonnelUserInfoReturnVo;
import com.starry.admin.modules.personnel.service.IPlayPersonnelAdminInfoService;
import com.starry.admin.modules.personnel.service.IPlayPersonnelGroupInfoService;
import com.starry.admin.modules.personnel.service.IPlayPersonnelWaiterInfoService;
import com.starry.admin.modules.system.mapper.SysRoleMapper;
import com.starry.admin.modules.system.mapper.SysUserMapper;
import com.starry.admin.modules.system.module.entity.SysRoleEntity;
import com.starry.admin.modules.system.module.entity.SysUserEntity;
import com.starry.admin.modules.system.module.entity.SysUserRoleEntity;
import com.starry.admin.modules.system.service.SysUserRoleService;
import com.starry.admin.modules.system.service.SysUserService;
import com.starry.admin.modules.system.vo.*;
import com.starry.admin.utils.SecurityUtils;
import com.starry.admin.utils.SmsUtils;
import com.starry.common.annotation.DataScope;
import com.starry.common.constant.Constants;
import com.starry.common.constant.UserConstants;
import com.starry.common.redis.RedisCache;
import com.starry.common.utils.IdUtils;
import com.starry.common.utils.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 后台用户表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2021-09-03
 */
@Slf4j
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity> implements SysUserService {

    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private SysUserRoleService userRoleService;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private IPlayClerkUserInfoService clerkUserInfoService;
    @Resource
    private IPlayPersonnelAdminInfoService playPersonnelAdminInfoService;
    @Resource
    private IPlayPersonnelGroupInfoService playClerkGroupInfoService;
    @Resource
    private IPlayPersonnelWaiterInfoService playClerkWaiterInfoService;
    @Resource
    private RedisCache redisCache;
    @Resource
    private SmsUtils smsUtils;

    @Override
    public List<SysUserEntity> selectAll() {
        LambdaQueryWrapper<SysUserEntity> lambdaWrapper = new LambdaQueryWrapper<>();
        lambdaWrapper.select(SysUserEntity::getUserId, SysUserEntity::getUserCode);
        return this.baseMapper.selectList(lambdaWrapper);

    }

    @Override
    public IPage<PlayPersonnelUserInfoReturnVo> selectByPage(PlayPersonnelUserInfoQueryVo vo) {
        MPJLambdaWrapper<SysUserEntity> lambdaWrapper = new MPJLambdaWrapper<>();
        lambdaWrapper.selectAll(SysUserEntity.class);
        // 店员表
        lambdaWrapper.selectAs(PlayClerkUserInfoEntity::getId, "clerkId")
                .selectAs(PlayClerkUserInfoEntity::getAvatar, "clerkAvatar")
                .selectAs(PlayClerkUserInfoEntity::getNickname, "clerkNickname");
        lambdaWrapper.leftJoin(PlayClerkUserInfoEntity.class, PlayClerkUserInfoEntity::getId, SysUserEntity::getUserId);
        if (StrUtil.isNotBlank(vo.getSysUserId())) {
            lambdaWrapper.eq(SysUserEntity::getUserId, vo.getSysUserId());
        }
        if (StrUtil.isNotBlank(vo.getUserCode())) {
            lambdaWrapper.eq(SysUserEntity::getUserCode, vo.getUserCode());
        }
        if (StrUtil.isNotBlank(vo.getRuleType())) {
            if ("0".equals(vo.getRuleType())) {
                lambdaWrapper.leftJoin(PlayClerkUserInfoEntity.class, PlayClerkUserInfoEntity::getSysUserId,
                        SysUserEntity::getUserId);
            } else if ("1".equals(vo.getRuleType())) {
                lambdaWrapper.leftJoin(PlayPersonnelWaiterInfoEntity.class, PlayPersonnelWaiterInfoEntity::getSysUserId,
                        SysUserEntity::getUserId);
            } else if ("2".equals(vo.getRuleType())) {
                lambdaWrapper.leftJoin(PlayPersonnelGroupInfoEntity.class, PlayPersonnelGroupInfoEntity::getSysUserId,
                        SysUserEntity::getUserId);
            }
        }
        if (vo.getAddTime() != null && vo.getAddTime().size() == 2) {
            lambdaWrapper.between(SysUserEntity::getAddTime, vo.getAddTime().get(0), vo.getAddTime().get(1));
        }

        return this.baseMapper.selectJoinPage(new Page<>(vo.getPageNum(), vo.getPageSize()),
                PlayPersonnelUserInfoReturnVo.class, lambdaWrapper);
    }

    @Override
    public SysUserEntity register(SysUserEntity user) {
        SysUserEntity newSysUserEntity = new SysUserEntity();
        BeanUtils.copyProperties(user, newSysUserEntity);
        // 查询是否有相同用户名的用户
        List<SysUserEntity> sysUserEntities = this.baseMapper.selectList(
                new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getUserCode, newSysUserEntity.getUserCode()));
        if (CollectionUtil.isNotEmpty(sysUserEntities)) {
            return null;
        }
        // 将密码进行加密操作
        String encodePassword = passwordEncoder.encode(user.getPassWord());
        newSysUserEntity.setPassWord(encodePassword);
        this.baseMapper.insert(newSysUserEntity);
        return newSysUserEntity;
    }

    @Override
    public SysUserEntity getUserByCode(String userCode) {
        List<SysUserEntity> users = baseMapper
                .selectList(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getUserCode, userCode));
        if (CollectionUtil.isNotEmpty(users)) {
            return users.get(0);
        }
        return null;
    }

    @Override
    public SysUserEntity selectUserByUserName(String userName) {
        return baseMapper.selectUserByUserName(userName);
    }

    @Override
    public SysUserEntity selectUserByUserNameAndTenantId(String userName, String tenantId) {
        return baseMapper.selectUserByUserNameAndTenantId(userName, tenantId);
    }

    @Override
    public IPage<SysUserEntity> listMemberPage(UserQueryVo queryVo) {
        Page<SysUserEntity> page = new Page<>(queryVo.getPageNum(), queryVo.getPageSize());
        return baseMapper.selectUserList(page, queryVo);
    }

    @Override
    public String checkUserNameUnique(String userCode) {
        // 查询是否有相同用户名的用户
        List<SysUserEntity> userList = this.baseMapper
                .selectList(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getUserCode, userCode));
        if (CollectionUtil.isNotEmpty(userList)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean create(SysUserEntity user) {
        // 将密码进行加密操作
        String encodePassword = passwordEncoder.encode(user.getPassWord());
        user.setPassWord(encodePassword);
        if (StrUtil.isBlankIfStr(user.getUserId())) {
            user.setUserId(IdUtils.getUuid());
        }
        boolean flag = save(user);
        if (flag) {
            // 新增用户角色信息
            flag = insertUserRole(user);
        }
        return flag;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean update(SysUserEntity user) {
        boolean flag = updateById(user);
        if (flag) {
            // 删除用户角色信息
            userRoleService.remove(
                    new LambdaQueryWrapper<SysUserRoleEntity>().eq(SysUserRoleEntity::getUserId, user.getUserId()));
            // 新增用户角色信息
            flag = insertUserRole(user);
        }
        return flag;

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean delete(List<String> ids) {
        if (CollectionUtil.isNotEmpty(ids)) {
            boolean flag = this.removeBatchByIds(ids);
            if (flag) {
                // 删除用户角色表
                userRoleService
                        .remove(new LambdaQueryWrapper<SysUserRoleEntity>().in(SysUserRoleEntity::getUserId, ids));
            }
        }
        return true;
    }

    @Override
    public SysUserEntity selectUserById(String userId) {
        if (StringUtils.isEmpty(userId)) {
            userId = SecurityUtils.getUserId();
        }
        baseMapper.selectById(userId);
        SysUserEntity data = baseMapper.selectUserById(userId);
        if (Objects.isNull(data)) {
            throw new RuntimeException("未查询到指定用户或该用户状态异常");
        }
        return data;
    }

    @Override
    public String selectUserRoleGroup(String userId) {
        List<SysRoleEntity> list = sysRoleMapper.selectRolePermissionByUserId(userId);
        if (CollectionUtil.isEmpty(list)) {
            return StringUtils.EMPTY;
        }
        return list.stream().map(SysRoleEntity::getRoleName).collect(Collectors.joining(","));
    }

    @Override
    public boolean updateUserAvatar(String userId, String avatar) {
        SysUserEntity user = getById(userId);
        if (user != null) {
            user.setAvatar(avatar);
            return updateById(user);
        }
        return false;
    }

    /**
     * 新增用户角色信息
     *
     * @param user
     *            用户对象
     */
    public boolean insertUserRole(SysUserEntity user) {
        if (user.getRoleIds() != null && user.getRoleIds().length > 0) {
            // 新增用户与角色管理
            List<SysUserRoleEntity> list = new ArrayList<>(user.getRoleIds().length);
            for (Long roleId : user.getRoleIds()) {
                SysUserRoleEntity ur = new SysUserRoleEntity();
                ur.setUserId(user.getUserId());
                ur.setRoleId(roleId);
                list.add(ur);
            }
            return userRoleService.saveBatch(list);
        }
        return true;
    }

    /**
     * 根据条件分页查询已分配用户角色列表
     *
     * @param userQueryVo
     *            用户信息
     * @return 用户信息集合信息
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public IPage<RoleUserResultVo> selectAllocatedList(SysUserQueryVo userQueryVo) {
        return baseMapper.selectAllocatedList(new Page<>(userQueryVo.getPageNum(), userQueryVo.getPageSize()),
                userQueryVo);
    }

    /**
     * 根据条件分页查询未分配用户角色列表
     *
     * @param user
     *            用户信息
     * @return 用户信息集合信息
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public IPage<RoleUserResultVo> selectUnallocatedList(SysUserQueryVo user) {
        return baseMapper.selectUnallocatedList(new Page<>(user.getPageNum(), user.getPageSize()), user);
    }

    @Override
    public boolean addV1(UserAddParam param) {
        long count = this
                .count(Wrappers.lambdaQuery(SysUserEntity.class).eq(SysUserEntity::getClerkId, param.getClerkId()));
        if (count > 0) {
            throw new RuntimeException("该店员已经成为员工了，无法再次添加~");
        }
        smsUtils.checkSmsCode(param.getMobile(), param.getSmsCode());
        PlayClerkUserInfoEntity clerk = clerkUserInfoService.selectById(param.getClerkId());
        SysUserEntity user = new SysUserEntity().setClerkId(param.getClerkId()).setMobile(param.getMobile())
                .setPassWord(SecurityUtils.encryptPassword(param.getMobile())).setUserCode(param.getMobile())
                .setUserNickname(clerk.getNickname()).setRealName(clerk.getNickname());
        user.setUserId(IdUtils.getUuid());
        user.setSuperAdmin(false);
        this.save(user);
        clerkUserInfoService.update(null,
                Wrappers.lambdaUpdate(PlayClerkUserInfoEntity.class)
                        .eq(PlayClerkUserInfoEntity::getId, param.getClerkId())
                        .set(PlayClerkUserInfoEntity::getSysUserId, user.getUserId()));
        return true;
    }

    @Override
    public List<SysUserEntityListVo> generatePageData(List<SysUserEntity> records) {
        return records.stream().map(ca -> {
            SysUserEntityListVo vo = new SysUserEntityListVo();
            BeanUtils.copyProperties(ca, vo);
            if (StringUtils.isNotEmpty(ca.getClerkId())) {
                vo.setClerkUserInfo(clerkUserInfoService.selectById(ca.getClerkId()));
            }
            // 查询角色
            List<SysUserEntityListVo.RoleVo> roleList = new ArrayList<>();
            PlayPersonnelAdminInfoEntity adminInfoEntity = playPersonnelAdminInfoService.selectByUserId(ca.getUserId());
            if (Objects.nonNull(adminInfoEntity)) {
                roleList.add(new SysUserEntityListVo.RoleVo("管理员", adminInfoEntity.getAdminName()));
            }
            PlayPersonnelGroupInfoEntity groupInfoEntity = playClerkGroupInfoService.selectByUserId(ca.getUserId());
            if (Objects.nonNull(groupInfoEntity)) {
                roleList.add(new SysUserEntityListVo.RoleVo("组长", groupInfoEntity.getLeaderName()));
            }
            PlayPersonnelWaiterInfoEntity waiterInfoEntity = playClerkWaiterInfoService.selectByUserId(ca.getUserId());
            if (Objects.nonNull(waiterInfoEntity)) {
                roleList.add(new SysUserEntityListVo.RoleVo("客服", waiterInfoEntity.getWaiterName()));
            }

            vo.setRoleVoList(roleList);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public void updatePassword(UpdateUserPasswordParam param) {
        selectUserById(param.getUserId());
        this.update(Wrappers.lambdaUpdate(SysUserEntity.class).eq(SysUserEntity::getUserId, param.getUserId())
                .set(SysUserEntity::getPassWord, SecurityUtils.encryptPassword(param.getPassword())));
    }

    @Override
    public void updateMobile(UpdateUserMobileParam param) {
        SysUserEntity user = selectUserById(param.getUserId());
        if (user.getMobile().equals(param.getMobile())) {
            throw new RuntimeException("新旧手机号不能相同~");
        }
        // 查询是否已有相同手机号
        long count = this.count(Wrappers.lambdaQuery(SysUserEntity.class)
                .eq(SysUserEntity::getMobile, param.getMobile()).ne(SysUserEntity::getUserId, param.getUserId()));
        if (count > 0) {
            throw new RuntimeException("系统中已有该手机号，无法录入~");
        }
        this.update(Wrappers.lambdaUpdate(SysUserEntity.class).eq(SysUserEntity::getUserId, param.getUserId())
                .set(SysUserEntity::getUserCode, param.getMobile()).set(SysUserEntity::getMobile, param.getMobile()));
    }

    @Override
    public void logoutUser(String uid) {
        String key = "login:resource:" + uid;
        Object object = redisCache.getCacheObject(key);
        if (Objects.isNull(object))
            return;

        String key2 = object.toString();
        redisCache.deleteObject(key2);
    }

    @Override
    public void updatePasswordV2(UpdateUserPasswordParamV2 param) {
        String userId = SecurityUtils.getUserId();
        SysUserEntity user = selectUserById(userId);
        if (!passwordEncoder.matches(param.getOldPassword(), user.getPassWord())) {
            throw new BadCredentialsException("旧密码不正确");
        }
        this.update(Wrappers.lambdaUpdate(SysUserEntity.class).eq(SysUserEntity::getUserId, userId)
                .set(SysUserEntity::getPassWord, SecurityUtils.encryptPassword(param.getNewPassword())));
        AsyncManager.me().execute(AsyncFactory.recordLoginLog(user.getUserCode(), Constants.LOGIN_SUCCESS, "修改密码"));
        logoutUser(userId);
    }
}
