package com.njcn.gather.user.user.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.sm.Sm4Utils;
import com.njcn.db.mybatisplus.constant.DbConstant;
import com.njcn.gather.user.pojo.constant.RoleConst;
import com.njcn.gather.user.pojo.constant.UserConst;
import com.njcn.gather.user.pojo.enums.UserResponseEnum;
import com.njcn.gather.user.user.mapper.SysUserMapper;
import com.njcn.gather.user.user.pojo.param.SysUserParam;
import com.njcn.gather.user.user.pojo.po.SysRole;
import com.njcn.gather.user.user.pojo.po.SysUser;
import com.njcn.gather.user.user.service.ISysUserRoleService;
import com.njcn.gather.user.user.service.ISysUserService;
import com.njcn.web.factory.PageFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author caozehui
 * @date 2024-11-08
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    private final ISysUserRoleService sysUserRoleService;

    @Override
    public Page<SysUser> listUser(SysUserParam.SysUserQueryParam queryParam) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(queryParam)) {
            queryWrapper.like(StrUtil.isNotBlank(queryParam.getName()), "sys_user.name", queryParam.getName())
                    .between(ObjectUtil.isAllNotEmpty(queryParam.getSearchBeginTime(), queryParam.getSearchEndTime()), "sys_user.Login_Time", queryParam.getSearchBeginTime(), queryParam.getSearchEndTime());
            //排序
            if (ObjectUtil.isAllNotEmpty(queryParam.getSortBy(), queryParam.getOrderBy())) {
                queryWrapper.orderBy(true, queryParam.getOrderBy().equals(DbConstant.ASC), StrUtil.toUnderlineCase(queryParam.getSortBy()));
            } else {
                queryWrapper.orderByDesc("sys_user.update_time");
            }
        } else {
            queryWrapper.orderByDesc("sys_user.update_time");
        }
        queryWrapper.ne("sys_user.state", UserConst.STATE_DELETE);
        Page<SysUser> page = this.baseMapper.selectPage(new Page<>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam)), queryWrapper);
        page.getRecords().forEach(sysUser -> {
            List<SysRole> sysRoles = sysUserRoleService.listRoleByUserId(sysUser.getId());
            sysUser.setRoleIds(sysRoles.stream().map(SysRole::getId).collect(Collectors.toList()));
            sysUser.setRoleNames(sysRoles.stream().map(SysRole::getName).collect(Collectors.toList()));
        });
        return page;
    }

    @Override
    public SysUser getUserByLoginName(String loginName) {
        return this.lambdaQuery().ne(SysUser::getState, UserConst.STATE_DELETE).eq(SysUser::getLoginName, loginName).one();
    }

    @Override
    public SysUser getUserByPhone(String phone, boolean isExcludeSelf, String id) {
        LambdaQueryWrapper<SysUser> lambdaQuery = new LambdaQueryWrapper<>();
        lambdaQuery.eq(SysUser::getPhone, phone).ne(SysUser::getState, UserConst.STATE_DELETE);
        if (isExcludeSelf) {
            lambdaQuery.ne(SysUser::getId, id);
        }
        return this.baseMapper.selectOne(lambdaQuery);
    }

    @Override
    public SysUser getUserByName(String name, boolean isExcludeSelf, String id) {
        LambdaQueryWrapper<SysUser> lambdaQuery = new LambdaQueryWrapper<>();
        lambdaQuery.eq(SysUser::getName, name).ne(SysUser::getState, UserConst.STATE_DELETE);
        if (isExcludeSelf) {
            lambdaQuery.ne(SysUser::getId, id);
        }
        return this.baseMapper.selectOne(lambdaQuery);
    }

    @Override
    public SysUser getUserByEmail(String email, boolean isExcludeSelf, String id) {
        LambdaQueryWrapper<SysUser> lambdaQuery = new LambdaQueryWrapper<>();
        lambdaQuery.eq(SysUser::getEmail, email).ne(SysUser::getState, UserConst.STATE_DELETE);
        if (isExcludeSelf) {
            lambdaQuery.ne(SysUser::getId, id);
        }
        return this.baseMapper.selectOne(lambdaQuery);
    }

    @Override
    @Transactional
    public boolean addUser(SysUserParam.SysUserAddParam addUserParam) {
        addUserParam.setName(addUserParam.getName().trim());
        addUserParam.setLoginName(addUserParam.getLoginName().trim());
        if (UserConst.SUPER_ADMIN.equals(addUserParam.getLoginName())) {
            throw new BusinessException(UserResponseEnum.SUPER_ADMIN_REPEAT);
        }
        if (!Objects.isNull(getUserByLoginName(addUserParam.getLoginName()))) {
            throw new BusinessException(UserResponseEnum.LOGIN_NAME_REPEAT);
        }
        checkRepeat(addUserParam, false, null);
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(addUserParam, sysUser);
        String secretkey = Sm4Utils.globalSecretKey;
        Sm4Utils sm4 = new Sm4Utils(secretkey);
        sysUser.setPassword(sm4.encryptData_ECB(sysUser.getPassword()));
        sysUser.setLoginTime(LocalDateTimeUtil.now());
        sysUser.setLoginErrorTimes(0);
        sysUser.setState(UserConst.STATE_ENABLE);
        boolean result = this.save(sysUser);
        sysUserRoleService.addUserRole(sysUser.getId(), addUserParam.getRoleIds());
        return result;
    }

    @Override
    @Transactional
    public boolean updateUser(SysUserParam.SysUserUpdateParam updateUserParam) {
        updateUserParam.setName(updateUserParam.getName().trim());
        checkRepeat(updateUserParam, true, updateUserParam.getId());
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(updateUserParam, sysUser);
        sysUserRoleService.updateUserRole(sysUser.getId(), updateUserParam.getRoleIds());
        return this.updateById(sysUser);
    }

    @Override
    @Transactional
    public boolean updatePassword(SysUserParam.SysUserUpdatePasswordParam param) {
        if (param.getOldPassword().equals(param.getNewPassword())) {
            throw new BusinessException(UserResponseEnum.PASSWORD_SAME);
        }
        SysUser user = lambdaQuery().ne(SysUser::getState, UserConst.STATE_DELETE).eq(SysUser::getId, param.getId()).one();
        if (ObjectUtil.isNotNull(user)) {
            String secretkey = Sm4Utils.globalSecretKey;
            Sm4Utils sm4 = new Sm4Utils(secretkey);
            if (sm4.encryptData_ECB(param.getOldPassword()).equals(user.getPassword())) {
                user.setPassword(sm4.encryptData_ECB(param.getNewPassword()));
                return this.updateById(user);
            }else {
                throw new BusinessException(UserResponseEnum.OLD_PASSWORD_ERROR);
            }
        }
        return false;
    }

    @Override
    @Transactional
    public boolean deleteUser(List<String> ids) {
        for (String id : ids) {
            List<SysRole> sysRoles = sysUserRoleService.listRoleByUserId(id);
            for (SysRole sysRole : sysRoles) {
                if (sysRole.getType().equals(RoleConst.TYPE_SUPER_ADMINISTRATOR)) {
                    throw new BusinessException(UserResponseEnum.SUPER_ADMIN_CANNOT_DELETE);     // 超级管理员角色不能删除
                }
            }
        }
        // 删除用户角色关联数据
        sysUserRoleService.deleteUserRoleByUserIds(ids);
        return this.lambdaUpdate()
                .set(SysUser::getState, UserConst.STATE_DELETE)
                .in(SysUser::getId, ids)
                .update();
    }

    @Override
    public SysUser getUserByLoginNameAndPassword(String loginName, String password) {
        String secretkey = Sm4Utils.globalSecretKey;
        Sm4Utils sm4 = new Sm4Utils(secretkey);
        return this.lambdaQuery().ne(SysUser::getState, UserConst.STATE_DELETE)
                .eq(SysUser::getLoginName, loginName)
                .eq(SysUser::getPassword, sm4.encryptData_ECB(password)).one();
    }

    @Override
    public boolean updateLoginTime(String userId) {
        return this.lambdaUpdate().eq(SysUser::getId, userId).set(SysUser::getLoginTime, LocalDateTimeUtil.now()).update();
    }

    /**
     * 校验重复
     *
     * @param sysUserParam  检查对象
     * @param isExcludeSelf 是否排除自己
     * @param id            排除自己id
     */
    private void checkRepeat(SysUserParam sysUserParam, boolean isExcludeSelf, String id) {
        if (!Objects.isNull(getUserByName(sysUserParam.getName(), isExcludeSelf, id))) {
            throw new BusinessException(UserResponseEnum.USER_NAME_REPEAT);
        }
        if (StringUtils.isNotBlank(sysUserParam.getPhone()) && !Objects.isNull(getUserByPhone(sysUserParam.getPhone(), isExcludeSelf, id))) {
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_FAIL);
        }
        if (StringUtils.isNotBlank(sysUserParam.getEmail()) && !Objects.isNull(getUserByEmail(sysUserParam.getEmail(), isExcludeSelf, id))) {
            throw new BusinessException(UserResponseEnum.REGISTER_EMAIL_FAIL);
        }
    }
}
