package com.qiaoba.module.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiaoba.api.auth.annotation.DataScope;
import com.qiaoba.api.auth.utils.SecurityUtil;
import com.qiaoba.api.system.entity.SysUser;
import com.qiaoba.api.system.entity.SysUserPost;
import com.qiaoba.api.system.entity.SysUserRole;
import com.qiaoba.api.system.entity.dto.SysUserDto;
import com.qiaoba.api.system.entity.param.SysUserParam;
import com.qiaoba.api.system.entity.vo.SysUserVo;
import com.qiaoba.common.base.exception.ServiceException;
import com.qiaoba.common.database.entity.PageQuery;
import com.qiaoba.common.database.entity.TableDataInfo;
import com.qiaoba.module.system.mapper.SysUserMapper;
import com.qiaoba.module.system.service.SysUserPostService;
import com.qiaoba.module.system.service.SysUserRoleService;
import com.qiaoba.module.system.service.SysUserService;
import com.qiaoba.module.system.templates.SysUserExport;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 用户管理 服务层实现
 *
 * @author ailanyin
 * @version 1.0
 * @since 2023-04-23 20:38:09
 */
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl implements SysUserService {

    private final SysUserMapper sysUserMapper;
    private final SysUserPostService sysUserPostService;
    private final SysUserRoleService sysUserRoleService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized int saveOrUpdate(SysUserDto dto, Boolean isUpdate) {
        int result = 0;
        SysUser sysUser = dtoToSysUser(dto, isUpdate);
        // 检验是否已存在
        checkAddOrUpdate(sysUser);
        if (isUpdate) {
            // 更新sysUser
            result = sysUserMapper.updateById(sysUser);
        } else {
            // 插入sysUser
            result = sysUserMapper.insert(sysUser);
        }
        // 处理角色
        handleUserRole(sysUser.getUserId(), dto.getRoleIds(), isUpdate);
        // 处理岗位
        handleUserPost(sysUser.getUserId(), dto.getPostIds(), isUpdate);
        return result;
    }

    @Override
    public SysUser selectById(String userId, Boolean hasPassword) {
        SysUser sysUser = sysUserMapper.selectById(userId);
        if (Objects.nonNull(sysUser) && !hasPassword) {
            sysUser.setPassword(null);
        }
        return sysUser;
    }

    @Override
    public SysUser selectByUsername(String username) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysUser::getUsername, username);
        return sysUserMapper.selectOne(wrapper);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteByIds(List<String> userIds) {
        // 删除和角色绑定
        sysUserRoleService.deleteByUserIds(userIds);
        // 删除和岗位绑定
        sysUserPostService.deleteByUserIds(userIds);
        return sysUserMapper.deleteBatchIds(userIds);
    }

    @Override
    public List<SysUser> selectList(SysUserParam sysUserParam) {
        return sysUserMapper.selectList(param2Wrapper(sysUserParam));
    }

    @Override
    public TableDataInfo<SysUser> selectPageList(SysUserParam param, PageQuery pageQuery) {
        return TableDataInfo.build(sysUserMapper.selectPage(pageQuery.build(), param2Wrapper(param)));
    }

    @Override
    @DataScope(userAlias = "u", deptAlias = "t2")
    public TableDataInfo<SysUserVo> selectVoPageList(SysUserParam param, PageQuery pageQuery) {
        Page<SysUserVo> page = sysUserMapper.selectVoPageList(pageQuery.build(), param);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<SysUserVo> selectAllocatedList(SysUserParam param, PageQuery pageQuery) {
        Page<SysUserVo> page = sysUserMapper.selectAllocatedList(pageQuery.build(), param);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo selectUnAllocatedList(SysUserParam param, PageQuery pageQuery) {
        Page<SysUserVo> page = sysUserMapper.selectUnAllocatedList(pageQuery.build(), param);
        return TableDataInfo.build(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleUserRole(String userId, Set<String> roleIds, boolean isUpdate) {
        if (isUpdate) {
            sysUserRoleService.deleteByUserId(userId);
        }
        if (CollUtil.isEmpty(roleIds)) {
            return;
        }
        List<SysUserRole> list = new ArrayList<>();
        for (String role : roleIds) {
            list.add(new SysUserRole(userId, role));
        }
        sysUserRoleService.insertBatch(list);
    }

    @Override
    public int updateById(SysUser sysUser) {
        return sysUserMapper.updateById(sysUser);
    }

    @Override
    public List<SysUserExport> selectExportData(SysUserParam param) {
        List<SysUserExport> list = sysUserMapper.selectExportData(param);
        list.forEach(export -> {
            export.setRole(CollectionUtil.join(export.getRoles(), "|"));
            export.setPost(CollectionUtil.join(export.getPosts(), "|"));
        });
        return list;
    }

    private QueryWrapper<SysUser> param2Wrapper(SysUserParam sysUserParam) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .orderByAsc(SysUser::getCreateTime)
                .eq(StrUtil.isNotBlank(sysUserParam.getDeptId()), SysUser::getDeptId, sysUserParam.getDeptId())
                .eq(StrUtil.isNotBlank(sysUserParam.getStatus()), SysUser::getStatus, sysUserParam.getStatus())
                .ge(Objects.nonNull(sysUserParam.getBeginTime()), SysUser::getCreateTime, sysUserParam.getBeginTime())
                .le(Objects.nonNull(sysUserParam.getEndTime()), SysUser::getCreateTime, sysUserParam.getEndTime())
                .like(StrUtil.isNotBlank(sysUserParam.getNickname()), SysUser::getNickname, sysUserParam.getNickname())
                .like(StrUtil.isNotBlank(sysUserParam.getPhone()), SysUser::getPhone, sysUserParam.getPhone());
        return wrapper;
    }

    private SysUser dtoToSysUser(SysUserDto dto, Boolean isUpdate) {
        if (StrUtil.isNotBlank(dto.getPassword())) {
            dto.setPassword(SecurityUtil.encryptPassword(dto.getPassword()));
        }
        SysUser sysUser = BeanUtil.copyProperties(dto, SysUser.class);
        if (isUpdate) {
            sysUser.setUsername(null);
            sysUser.setPassword(null);
            sysUser.setUpdateTime(new Date());
            sysUser.setUpdateUser(SecurityUtil.getLoginUsername());
        } else {
            sysUser.setCreateTime(new Date());
            sysUser.setCreateUser(SecurityUtil.getLoginUsername());
        }
        return sysUser;
    }

    @Override
    public void checkAddOrUpdate(SysUser sysUser) {
        if (StrUtil.isNotBlank(sysUser.getUsername()) && checkUsernameNotUnique(sysUser)) {
            throw new ServiceException("登录账号已存在");
        }
        if (StrUtil.isNotBlank(sysUser.getPhone()) && checkPhoneNotUnique(sysUser)) {
            throw new ServiceException("手机号已存在");
        }
        if (StrUtil.isNotBlank(sysUser.getEmail()) && checkEmailNotUnique(sysUser)) {
            throw new ServiceException("邮箱号已存在");
        }
    }

    /**
     * 校验用户名称是否唯一
     *
     * @param sysUser 用户信息
     * @return 结果
     */
    private boolean checkUsernameNotUnique(SysUser sysUser) {
        return StrUtil.isNotBlank(sysUserMapper.checkUsernameUnique(sysUser));
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param sysUser 用户信息
     * @return 结果
     */
    private boolean checkPhoneNotUnique(SysUser sysUser) {
        return StrUtil.isNotBlank(sysUserMapper.checkPhoneUnique(sysUser));
    }

    /**
     * 校验email是否唯一
     *
     * @param sysUser 用户信息
     * @return 结果
     */
    private boolean checkEmailNotUnique(SysUser sysUser) {
        return StrUtil.isNotBlank(sysUserMapper.checkEmailUnique(sysUser));

    }

    @Transactional(rollbackFor = Exception.class)
    public void handleUserPost(String userId, Set<String> postIds, boolean isUpdate) {
        if (isUpdate) {
            sysUserPostService.deleteByUserId(userId);
        }
        if (CollUtil.isEmpty(postIds)) {
            return;
        }
        List<SysUserPost> list = new ArrayList<>();
        for (String postId : postIds) {
            list.add(new SysUserPost(userId, postId));
        }
        sysUserPostService.insertBatch(list);
    }

}
