package com.dsk.system.service;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.secure.SaBase64Util;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.RegexPool;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dsk.common.constant.CacheConstants;
import com.dsk.common.constant.Constants;
import com.dsk.common.constant.GlobalConstants;
import com.dsk.common.constant.TenantConstants;
import com.dsk.common.core.domain.dto.RoleDTO;
import com.dsk.common.core.domain.event.LogininforEvent;
import com.dsk.common.core.domain.model.LoginBody;
import com.dsk.common.core.domain.model.LoginUser;
import com.dsk.common.core.domain.model.XcxLoginUser;
import com.dsk.common.enums.DeviceType;
import com.dsk.common.enums.LoginType;
import com.dsk.common.enums.TenantStatus;
import com.dsk.common.enums.UserStatus;
import com.dsk.common.exception.user.CaptchaException;
import com.dsk.common.exception.user.CaptchaExpireException;
import com.dsk.common.exception.user.UserException;
import com.dsk.common.helper.LoginHelper;
import com.dsk.common.tenant.exception.TenantException;
import com.dsk.common.tenant.helper.TenantBroker;
import com.dsk.common.tenant.helper.TenantHelper;
import com.dsk.common.utils.DateUtils;
import com.dsk.common.utils.MessageUtils;
import com.dsk.common.utils.ServletUtils;
import com.dsk.common.utils.StringUtils;
import com.dsk.common.utils.redis.RedisUtils;
import com.dsk.common.utils.spring.SpringUtils;
import com.dsk.system.domain.SysTenant;
import com.dsk.system.domain.SysUser;
import com.dsk.system.domain.vo.LoginVo;
import com.dsk.system.domain.vo.SysTenantVo;
import com.dsk.system.mapper.SysTenantMapper;
import com.dsk.system.mapper.SysUserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.function.Supplier;

/**
 * 登录校验方法
 *
 * @author Lion Li
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class SysLoginService {

    private final SysUserMapper userMapper;
    private final ISysConfigService configService;
    private final SysPermissionService permissionService;
    private final ISysTenantService sysTenantService;

    @Value("${captcha.enable}")
    private boolean captchaEnabled;

    @Value("${user.password.maxRetryCount}")
    private Integer maxRetryCount;

    @Value("${user.password.lockTime}")
    private Integer lockTime;

    /**
     * 登录验证
     *
     * @param loginBody 唯一标识
     * @return 结果
     */
    public LoginVo passwordLogin(LoginBody loginBody) {
        String tenantId = loginBody.getTenantId();
        String username = loginBody.getUsername();
        String password = SaBase64Util.decode(loginBody.getPassword());
        String code = loginBody.getCode();
        String uuid = loginBody.getUuid();
        // 验证码开关
        if (captchaEnabled) {
            validateCaptcha(username, code, uuid);
        }

        if(ReUtil.isMatch(RegexPool.MOBILE, username)) {
          String  defaultTenantId = RedisUtils.getCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username);
            log.info("登录用户：{} 获取缓存默认租户:"+tenantId, username);
            if(StrUtil.isNotBlank(defaultTenantId)){
                defaultTenantId= checkDefaultTenant(defaultTenantId,username);
                tenantId=defaultTenantId;
            }
        }

        //查询手机号绑定的所有用户
        if (StrUtil.isEmpty(tenantId)) {
            List<SysUser> sysUsers = queryListByPhone(username);
            if (CollectionUtil.isEmpty(sysUsers)) {
                log.info("登录用户：{} 不存在.", username);
                throw new UserException("user.not.exists", username);
            } else if (sysUsers.size() > 1) {
                //处理存在多个用户的情况，取一个最新租户
                SysUser sysUser = sysUsers.get(0);
                if (ObjectUtil.isEmpty(sysUser)) {
                    log.info("登录用户：{} 不存在.", username);
                    throw new UserException("user.not.exists", username);
                }
                tenantId = sysUser.getTenantId();
            }else {
                SysUser sysUser = sysUsers.get(0);
                tenantId = sysUser.getTenantId();
            }
        }

        // 校验租户
        if (tenantId != null) {
            checkTenant(tenantId);
        }
        if (tenantId == null || "".equals(tenantId)) {
            tenantId = TenantConstants.DEFAULT_TENANT_ID;
        }
        TenantHelper.setTenantId(tenantId);
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
//        SysUser user = loadUserByUsername(username);
//        return TenantBroker.applyAs(tenantId, (id -> {

        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        SysUser user = loadUserByUsername(username);
        checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword()));
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        LoginUser loginUser = buildLoginUser(user);
        // 生成token
        LoginHelper.loginByDevice(loginUser, DeviceType.PC);

        recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId(), username);

//        RedisUtils.setCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username, TenantHelper.getTenantId(), Duration.ofDays(30));

        LoginVo loginVo = new LoginVo();
        loginVo.setTenantId(TenantHelper.getTenantId());
        loginVo.setAccessToken(StpUtil.getTokenValue());
        loginVo.setExpireIn(StpUtil.getTokenTimeout());
        return loginVo;
//        }));
//        return StpUtil.getTokenValue();
    }


    /**
     * 登录验证
     *
     * @param username 用户名
     * @param password 密码
     * @param code     验证码
     * @param uuid     唯一标识
     * @return 结果
     */
    public String login(String username, String password, String code, String uuid) {
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        // 验证码开关
        if (captchaEnabled) {
            validateCaptcha(username, code, uuid);
        }
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        SysUser user = loadUserByUsername(username);
        checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword()));
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        LoginUser loginUser = buildLoginUser(user);
        // 生成token
        LoginHelper.loginByDevice(loginUser, DeviceType.PC);

        recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId(), username);
        return StpUtil.getTokenValue();
    }

    public LoginVo smsLogin(String username, String smsCode) {
        String tenantId=null;
        if(ReUtil.isMatch(RegexPool.MOBILE, username)) {
            String  defaultTenantId = RedisUtils.getCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username);
            log.info("登录用户：{} 获取缓存默认租户:"+tenantId, username);
            if(StrUtil.isNotBlank(defaultTenantId)){
                defaultTenantId= checkDefaultTenant(defaultTenantId,username);
                tenantId=defaultTenantId;
            }
        }

        //查询手机号绑定的所有用户
        if (StrUtil.isEmpty(tenantId)) {
            List<SysUser> sysUsers = queryListByPhone(username);
            if (CollectionUtil.isEmpty(sysUsers)) {
                log.info("登录用户：{} 不存在.", username);
                throw new UserException("user.not.exists", username);
            } else if (sysUsers.size() > 1) {
                //处理存在多个用户的情况，取一个最新租户
                SysUser sysUser = sysUsers.get(0);
                if (ObjectUtil.isEmpty(sysUser)) {
                    log.info("登录用户：{} 不存在.", username);
                    throw new UserException("user.not.exists", username);
                }
                tenantId = sysUser.getTenantId();
            }else {
                SysUser sysUser = sysUsers.get(0);
                tenantId = sysUser.getTenantId();
            }
        }

        // 校验租户
        if (tenantId != null) {
            checkTenant(tenantId);
        }
        if (tenantId == null || "".equals(tenantId)) {
            tenantId = TenantConstants.DEFAULT_TENANT_ID;
        }
        TenantHelper.setTenantId(tenantId);
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
//        SysUser user = loadUserByUsername(username);
//        return TenantBroker.applyAs(tenantId, (id -> {

        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        SysUser user = loadUserByUsername(username);
        checkLogin(LoginType.SMS, username, () -> !validateSmsCode(username, smsCode));
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        LoginUser loginUser = buildLoginUser(user);
        // 生成token
        LoginHelper.loginByDevice(loginUser, DeviceType.PC);

        recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId(), username);

        LoginVo loginVo = new LoginVo();
        loginVo.setTenantId(TenantHelper.getTenantId());
        loginVo.setAccessToken(StpUtil.getTokenValue());
        loginVo.setExpireIn(StpUtil.getTokenTimeout());
        return loginVo;
    }

    public String emailLogin(String email, String emailCode) {
        // 通过手邮箱查找用户
        SysUser user = loadUserByEmail(email);

        checkLogin(LoginType.EMAIL, user.getUserName(), () -> !validateEmailCode(email, emailCode));
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        LoginUser loginUser = buildLoginUser(user);
        // 生成token
        LoginHelper.loginByDevice(loginUser, DeviceType.APP);

        recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId(), user.getUserName());
        return StpUtil.getTokenValue();
    }

    public String xcxLogin(String xcxCode) {
        // xcxCode 为 小程序调用 wx.login 授权后获取
        // todo 以下自行实现
        // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
        String openid = "";

        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        SysUser user = loadUserByOpenid(openid);

        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        XcxLoginUser loginUser = new XcxLoginUser();
        loginUser.setUserId(user.getUserId());
        loginUser.setUsername(user.getUserName());
        loginUser.setUserType(user.getUserType());
        loginUser.setOpenid(openid);
        // 生成token
        LoginHelper.loginByDevice(loginUser, DeviceType.XCX);

        recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId(), user.getUserName());
        return StpUtil.getTokenValue();
    }

    /**
     * 退出登录
     */
    public void logout() {
        try {
            LoginUser loginUser = LoginHelper.getLoginUser();
            if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
                // 超级管理员 登出清除动态租户
                TenantHelper.clearDynamic();
            }
            recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
        } catch (NotLoginException ignored) {
        } finally {
            try {
                StpUtil.logout();
            } catch (NotLoginException ignored) {
            }
        }
    }

    /**
     * 记录登录信息
     *
     * @param username 用户名
     * @param status   状态
     * @param message  消息内容
     */
    private void recordLogininfor(String username, String status, String message) {
        LogininforEvent logininforEvent = new LogininforEvent();
        logininforEvent.setUsername(username);
        logininforEvent.setStatus(status);
        logininforEvent.setMessage(message);
        logininforEvent.setRequest(ServletUtils.getRequest());
        SpringUtils.context().publishEvent(logininforEvent);
    }

    /**
     * 校验短信验证码
     */
    private boolean validateSmsCode(String phonenumber, String smsCode) {
        String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
        if (StringUtils.isBlank(code)) {
            recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
            throw new CaptchaExpireException();
        }
        return code.equals(smsCode);
    }

    /**
     * 校验邮箱验证码
     */
    private boolean validateEmailCode(String email, String emailCode) {
        String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
        if (StringUtils.isBlank(code)) {
            recordLogininfor(email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
            throw new CaptchaExpireException();
        }
        return code.equals(emailCode);
    }

    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code     验证码
     * @param uuid     唯一标识
     */
    public void validateCaptcha(String username, String code, String uuid) {
        String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
        String captcha = RedisUtils.getCacheObject(verifyKey);
        RedisUtils.deleteObject(verifyKey);
        if (captcha == null) {
            recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
            throw new CaptchaException();
        }
    }

    private SysUser loadUserByUsername(String username) {
        SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
            .select(SysUser::getUserName, SysUser::getStatus)
            .eq(SysUser::getUserName, username)
            .or().eq(SysUser::getPhonenumber, username));
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户：{} 不存在.", username);
            throw new UserException("user.not.exists", username);
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户：{} 已被停用.", username);
            throw new UserException("user.blocked", username);
        }
        return userMapper.selectUserByUserName(user.getUserName());
    }

    private SysUser loadUserByPhonenumber(String phonenumber) {
        SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
            .select(SysUser::getPhonenumber, SysUser::getStatus)
            .eq(SysUser::getPhonenumber, phonenumber));
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户：{} 不存在.", phonenumber);
            throw new UserException("user.not.exists", phonenumber);
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户：{} 已被停用.", phonenumber);
            throw new UserException("user.blocked", phonenumber);
        }
        return userMapper.selectUserByPhonenumber(phonenumber);
    }

    private SysUser loadUserByEmail(String email) {
        SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
            .select(SysUser::getPhonenumber, SysUser::getStatus)
            .eq(SysUser::getEmail, email));
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户：{} 不存在.", email);
            throw new UserException("user.not.exists", email);
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户：{} 已被停用.", email);
            throw new UserException("user.blocked", email);
        }
        return userMapper.selectUserByEmail(email);
    }

    private SysUser loadUserByOpenid(String openid) {
        // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
        // todo 自行实现 userService.selectUserByOpenid(openid);
        SysUser user = new SysUser();
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户：{} 不存在.", openid);
            // todo 用户不存在 业务逻辑自行实现
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户：{} 已被停用.", openid);
            // todo 用户已被停用 业务逻辑自行实现
        }
        return user;
    }

    /**
     * 构建登录用户
     */
    public LoginUser buildLoginUser(SysUser user) {
        LoginUser loginUser = new LoginUser();
        loginUser.setTenantId(user.getTenantId());
        loginUser.setUserId(user.getUserId());
        loginUser.setDeptId(user.getDeptId());
        loginUser.setUsername(user.getUserName());
        loginUser.setNickname(user.getNickName());
        loginUser.setUserType(user.getUserType());
        loginUser.setUserPhone(user.getPhonenumber());
        loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
        loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
        loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName());
        List<RoleDTO> roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class);
        loginUser.setRoles(roles);
        return loginUser;
    }


    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId, String username) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(ServletUtils.getClientIP());
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUser.setUpdateBy(username);
        userMapper.updateById(sysUser);
    }

    /**
     * 登录校验
     */
    private void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) {
        String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
        String loginFail = Constants.LOGIN_FAIL;

        // 获取用户登录错误次数，默认为0 (可自定义限制策略 例如: key + username + ip)
        int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0);
        // 锁定时间内登录 则踢出
        if (errorNumber >= maxRetryCount) {
            recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
            throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
        }

        if (supplier.get()) {
            // 错误次数递增
            errorNumber++;
            RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
            // 达到规定错误次数 则锁定登录
            if (errorNumber >= maxRetryCount) {
                recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
                throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
            } else {
                // 未达到规定错误次数
                recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
                throw new UserException(loginType.getRetryLimitCount(), errorNumber);
            }
        }

        // 登录成功 清空错误次数
        RedisUtils.deleteObject(errorKey);
    }

    public void checkTenant(String tenantId) {
        if (!TenantHelper.isEnable()) {
            return;
        }
        if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
            return;
        }
        SysTenantVo tenant = sysTenantService.queryByTenantId(tenantId);
        if (ObjectUtil.isNull(tenant)) {
            log.info("登录企业：{} 不存在.", tenantId);
            throw new TenantException("company.not.exists");
        } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) {
            log.info("登录企业：{} 已被停用.", tenant.getCompanyName());
            throw new TenantException("company.blocked");
        } else if (ObjectUtil.isNotNull(tenant.getExpireTime())
            && new Date().after(tenant.getExpireTime())) {
            log.info("登录企业：{} 已超过有效期.", tenant.getCompanyName());
            throw new TenantException("company.expired");
        }
    }


    public String checkDefaultTenant(String tenantId,String phoneNumber) {
        if (!TenantHelper.isEnable()) {
            return null;
        }
        if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
            return null;
        }
        SysTenantVo tenant = sysTenantService.queryByTenantId(tenantId);
        if (ObjectUtil.isNull(tenant)) {
            log.info("登录企业：{} 不存在.", tenantId);
            RedisUtils.deleteObject(GlobalConstants.PHONE_DEFAULT_TENANT + phoneNumber);
            return null;
        } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) {
            log.info("登录企业：{} 已被停用.", tenant.getCompanyName());
            RedisUtils.deleteObject(GlobalConstants.PHONE_DEFAULT_TENANT + phoneNumber);
            return null;
        } else if (ObjectUtil.isNotNull(tenant.getExpireTime())
                && new Date().after(tenant.getExpireTime())) {
            log.info("登录企业：{} 已超过有效期.", tenant.getCompanyName());
            RedisUtils.deleteObject(GlobalConstants.PHONE_DEFAULT_TENANT + phoneNumber);
            return null;
        }
        return tenantId;
    }


    public List<SysTenantVo> tenantListByAccount(String username) {
        return TenantHelper.ignore(() -> sysTenantService.selectTenantList(username));
    }

//    public   List<SysTenantVo> selectTenantList(String username){
//
//    }


    public List<SysUser> queryListByPhone(String username) {
        return TenantHelper.ignore(() -> {
            List<SysUser> sysUsers = null;
            if (ReUtil.isMatch(RegexPool.MOBILE, username)) {

                LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<SysUser>()
                    .select(SysUser::getUserName, SysUser::getStatus, SysUser::getTenantId)
                    .eq(SysUser::getPhonenumber, username)
                    .orderByDesc(SysUser::getUserId);
                sysUsers = userMapper.selectList(lqw);
            } else {
                LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<SysUser>()
                    .select(SysUser::getUserName, SysUser::getStatus, SysUser::getTenantId)
                    .eq(SysUser::getUserName, username)
                    .orderByDesc(SysUser::getUserId);
                sysUsers = userMapper.selectList(lqw);
            }
            return sysUsers;
        });
    }


    public LoginVo switchTenant(String tenantId) {

        //获取当前登录信息
        Long userId = LoginHelper.getUserId();
        Assert.notNull(userId, "企业切换失败！");
        // 如果 切换租户和当前登录租户一致，仅保存默认租户
        LoginUser loginUserVo = LoginHelper.getLoginUser();
        if(tenantId.equals(loginUserVo.getTenantId())){
            //保存当前账号的默认租户
            String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + loginUserVo.getUserPhone();
            RedisUtils.setCacheObject(defaultTenantKey,tenantId, Duration.ofDays(90));
            LoginVo loginVo = new LoginVo();
            loginVo.setTenantId(TenantHelper.getTenantId());
            loginVo.setAccessToken(StpUtil.getTokenValue());
            loginVo.setExpireIn(StpUtil.getTokenTimeout());
            return loginVo;
        }

        SysUser sysUser = TenantHelper.ignore(() -> {
            return userMapper.selectUserById(userId);
        });
        Assert.notNull(sysUser, "用户信息为空，企业切换失败！");
        if (StrUtil.isEmpty(sysUser.getPhonenumber())) {
            Assert.notNull(sysUser, "用户手机号为空，企业切换失败！");
        }
        //退出登录
        StpUtil.logout();
        String tokenValue = StpUtil.getTokenValueByLoginId(userId);
        StpUtil.logoutByTokenValue(tokenValue);
        StpUtil.kickoutByTokenValue(tokenValue);
//        RedisUtils.deleteKeys("*"+tokenValue+"*");


        //重新登录
        TenantHelper.setTenantId(tenantId);
        String username = sysUser.getPhonenumber();
        SysUser user = loadUserByUsername(sysUser.getPhonenumber());
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        LoginUser loginUser = buildLoginUser(user);
        // 生成token
        LoginHelper.loginByDevice(loginUser, DeviceType.PC);


        log.info("当前租户由"+sysUser.getTenantId()+"切换为"+tenantId);
        //保存当前账号的默认租户
        String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + loginUser.getUserPhone();
        RedisUtils.setCacheObject(defaultTenantKey,tenantId, Duration.ofDays(90));
        recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId(), username);

        LoginVo loginVo = new LoginVo();
        loginVo.setTenantId(TenantHelper.getTenantId());
        loginVo.setAccessToken(StpUtil.getTokenValue());
        loginVo.setExpireIn(StpUtil.getTokenTimeout());
        return loginVo;
    }
}
