package com.simuwang.manage.service.impl.system;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.simuwang.base.common.support.MybatisPage;
import com.simuwang.base.common.support.command.BaseAddCmd;
import com.simuwang.base.common.support.command.BaseEditCmd;
import com.simuwang.base.common.support.command.BaseIdsCmd;
import com.simuwang.base.common.support.command.BaseIdStatusCmd;
import com.simuwang.base.common.support.dos.OnlyIdNameDO;
import com.simuwang.base.common.support.query.PageQuery;
import com.simuwang.base.common.support.service.IService;
import com.simuwang.base.common.support.vo.OnlyIdNameVO;
import com.simuwang.base.components.UserAuthService;
import com.simuwang.base.config.DaqProperties;
import com.simuwang.base.mapper.system.SysUserMapper;
import com.simuwang.base.pojo.dos.sys.SysRoleUserDO;
import com.simuwang.base.pojo.dos.sys.SysUserDO;
import com.simuwang.base.pojo.dto.GetByIdQuery;
import com.simuwang.base.pojo.dto.sys.*;
import com.simuwang.base.pojo.vo.sys.SysRoleUserVO;
import com.simuwang.base.pojo.vo.sys.SysUserVO;
import com.simuwang.manage.service.system.SysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class SysUserServiceImpl implements SysUserService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final SysUserMapper mapper;
    private final DaqProperties properties;
    private final UserAuthService userAuthService;

    public SysUserServiceImpl(SysUserMapper mapper, DaqProperties properties, UserAuthService userAuthService) {
        this.mapper = mapper;
        this.properties = properties;
        this.userAuthService = userAuthService;
    }

    @Override
    public String[] selectColumns() {
        return IService.extColumns(DEFAULT_SELECT_COLUMNS,
                "user_id", "user_name", "email", "phonenumber", "sex", "avatar", "status");
    }

    @Override
    public <Q extends PageQuery> void wrapQuery(QueryWrapper<SysUserDO> wrapper, Q query) {
        // 排除超级管理员
        wrapper.notIn("user_id", 0, 1);
        UserQuery params = (UserQuery) query;
        String keyword = params.getKeyword();
        if (StrUtil.isNotBlank(keyword)) {
            wrapper.like("user_name", keyword);
        }
        if (StrUtil.isNotBlank(params.getEmail())) {
            wrapper.like("email", params.getEmail());
        }
        if (StrUtil.isNotBlank(params.getPhonenumber())) {
            wrapper.like("phonenumber", params.getPhonenumber());
        }
        if (params.getStatus() != null) {
            wrapper.eq("status", params.getStatus());
        }
    }

    @Override
    public MybatisPage<SysUserVO> convertPage(Page<SysUserDO> page, QueryWrapper<SysUserDO> wrapper) {
        IPage<SysUserDO> entityPage = this.mapper.selectPage(page, wrapper);
        return MybatisPage.ofList(entityPage, SysUserDO::toVo);
    }

    @Override
    public <Q extends PageQuery> MybatisPage<SysRoleUserVO> findMultiPage(Q query) {
        RoleUserQuery params = (RoleUserQuery) query;
        List<SysRoleUserDO> dataList = this.mapper.roleUserPage(params);
        List<SysRoleUserVO> records = dataList.stream().map(SysRoleUserDO::toVo).collect(Collectors.toList());
        long count = this.mapper.countRoleUser(params);
        return MybatisPage.of(count, records);
    }

    @Override
    public <C extends BaseAddCmd<SysUserDO>> void insert(C command) {
        UserAddCmd cmd = (UserAddCmd) command;
        SysUserDO entity = cmd.toEntity();
        String originalPwd = cmd.getPassword();
        if (StrUtil.isBlank(originalPwd)) {
            originalPwd = this.properties.getDefaultPwd();
        }
        String publicKey = this.properties.getSecurityRsa().getPublicKey();
        String password = new RSA(null, publicKey).encryptBase64(originalPwd, KeyType.PublicKey);
        entity.setPassword(password);
        this.mapper.insert(entity);
    }

    @Override
    public <C extends BaseEditCmd<SysUserDO>> void update(C command) {
        UserEditCmd cmd = (UserEditCmd) command;
        SysUserDO entity = cmd.toEntity();
        String originalPwd = cmd.getPassword();
        String publicKey = this.properties.getSecurityRsa().getPublicKey();
        String password = new RSA(null, publicKey).encryptBase64(originalPwd, KeyType.PublicKey);
        entity.setPassword(password);
        this.mapper.updateById(entity);
    }

    @Override
    public <C extends BaseIdStatusCmd> void updateStatus(C command) {
        SysUserDO user = new SysUserDO();
        user.setUserId(command.getId());
        user.setStatus(command.getStatus());
        this.mapper.updateById(user);
    }

    @Override
    public <C extends BaseIdsCmd> void delete(C command) {
        List<Integer> ids = command.getIds();
        this.mapper.deleteByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindRoles(UserRoleBindCmd command) {
        Integer userId = command.getUserId();
        int i = this.mapper.delUserRoleByUserId(userId);
        int j = this.mapper.batchUserRoles(userId, command.getRoleIds());
        if (this.logger.isInfoEnabled()) {
            this.logger.info("绑定用户{} 角色时删除了{}条记录，新增{}条记录", userId, i, j);
        }
    }

    @Override
    public List<OnlyIdNameVO> getUserRoles(GetByIdQuery query) {
        List<OnlyIdNameDO> dataList = this.userAuthService.userBindRoles(query.getId());
        return dataList.stream().map(OnlyIdNameDO::toVo).collect(Collectors.toList());
    }
}
