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

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.ema.admin.modules.system.converter.SysMenuConverter;
import com.ema.admin.modules.system.converter.SysUserConverter;
import com.ema.admin.modules.system.entity.SysMenu;
import com.ema.admin.modules.system.entity.SysRole;
import com.ema.admin.modules.system.entity.SysUser;
import com.ema.admin.modules.system.enums.SysUserEnum;
import com.ema.admin.modules.system.service.*;
import com.ema.admin.modules.system.vo.*;
import com.ema.common.exceptions.MyAssert;
import com.ema.common.utils.TreeUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 用户登录注册授权管理 服务层实现。
 */
@Service
public class SysAuthServiceImpl implements SysAuthService {

    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    private SysMenuService sysMenuService;
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private SysEmailService sysEmailService;
    @Resource
    private SysUserConverter sysUserConverter;
    @Resource
    private SysMenuConverter sysMenuConverter;


    public static final String MENU = "menu";
    public static final String ROLE = "role";

    @Override
    public SysUserVo login(SysUserPwdVo pwdVo) {
        SysUser sysUser = sysUserService.getByAccount(pwdVo.getAccount());
        MyAssert.isTrue(Objects.nonNull(sysUser)
                        && SaSecureUtil.md5(pwdVo.getPwd()).equals(sysUser.getPassword()),
                "账号或密码错误！");
        MyAssert.isTrue(sysUser.getStatus().equals(SysUserEnum.Status.ENABLE.getValue()),
                "账号已被禁用！");
        SysUserVo userVo = this.setLoginSession(sysUser);
        return userVo;
    }

    @Override
    public void forgotPassword(SysUserForgotPwdVo forgotPwdVo) {

        // 根据邮箱查询用户
        SysUser sysUser = sysUserService.queryChain()
                .eq(SysUser::getEmail, forgotPwdVo.getEmail()).one();
        MyAssert.notNull(sysUser, "该邮箱未注册，请先注册！");

        // 验证邮箱验证码
        sysEmailService.verifyCode(forgotPwdVo.getEmail(), forgotPwdVo.getCode());

        // 更新密码
        sysUser.setPassword(SaSecureUtil.md5(forgotPwdVo.getNewPwd()));
        boolean updateResult = sysUserService.updateById(sysUser);
        MyAssert.isTrue(updateResult, "密码重置失败，请稍后重试！");
    }

    /**
     * 获取用户登录信息
     *
     * @param sysUser
     * @return
     */
    private SysUserVo setLoginSession(SysUser sysUser) {
        SysUserVo userVo = sysUserConverter.toSysUserVo(sysUser);

        // 会话登录：参数填写要登录的账号id
        StpUtil.login(userVo.getId());
        //获取登录后的token
        userVo.setToken(StpUtil.getTokenValue());
        StpUtil.getSession().set(userVo.getToken(), userVo); // 缓存 userVo 对象

        //查询用户角色
        List<SysRole> sysRoles = sysRoleService.getRoleByUserId(userVo.getId());
        MyAssert.isTrue(CollUtil.isNotEmpty(sysRoles), "用户角色不存在，请联系管理员！");
        userVo.setRoleKeys(sysRoles.stream().map(SysRole::getRoleKey).distinct().collect(Collectors.toList()));

        //查询用户权限
        List<SysMenu> sysMenus = sysMenuService.getMenuByRoles(sysRoles);
        userVo.setPermsKeys(sysMenus.stream().map(SysMenu::getPerms).filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList()));
        StpUtil.getSession().set(ROLE + userVo.getToken(), sysRoles);//缓存角色信息
        StpUtil.getSession().set(MENU + userVo.getToken(), sysMenus);
        return userVo;
    }

    @Override
    public SysUserVo getCurrentUser() {
        return StpUtil.getSession().getModel(StpUtil.getTokenValue(), SysUserVo.class);
    }

    @Override
    public List<SysMenuVo> getCurrentUserMenuTree() {
        List<SysMenu> menuList = this.getCurrentUserMenus();
        List<SysMenuVo> menuVoList = sysMenuConverter.toSysMenuVo(menuList);
        // 构建树形菜单
        return TreeUtil.buildTree(menuVoList, null);
    }

    @Override
    public List<SysMenu> getCurrentUserMenus() {
        SysUserVo userVo = this.getCurrentUser();
        return (List<SysMenu>) StpUtil.getSession().get(MENU + userVo.getToken());
    }

    @Override
    public List<SysRole> getCurrentUseRoles() {
        SysUserVo userVo = this.getCurrentUser();
        return (List<SysRole>) StpUtil.getSession().get(ROLE + userVo.getToken());
    }

    @Override
    public void updatePwd(SysUserPwdUpdateVo updatePwdVo) {
        SysUserVo userVo = this.getCurrentUser();
        SysUser sysUser = sysUserService.getById(userVo.getId());
        MyAssert.isTrue(sysUser != null
                        && SaSecureUtil.md5(updatePwdVo.getOldPwd()).equals(sysUser.getPassword()),
                "原密码错误！");
        sysUser.setPassword(SaSecureUtil.md5(updatePwdVo.getNewPwd()));
        sysUserService.updateById(sysUser);
    }


}
