package cn.iocoder.yudao.module.system.service.tenant;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRenewalReqVO;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenantbalance.TenantBalanceDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
import cn.iocoder.yudao.module.system.dal.mysql.tenantbalance.TenantBalanceMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.enums.agencyTenantPackage.PackageTypeEnum;
import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
import cn.iocoder.yudao.module.system.enums.tenant.TenantEnum;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler;
import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler;
import cn.iocoder.yudao.module.system.service.tenantagencypackage.TenantAgencyPackageService;
import cn.iocoder.yudao.module.system.service.tenantbalance.TenantBalanceService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static java.util.Collections.singleton;

/**
 * 租户 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class TenantServiceImpl implements TenantService {

    @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
    @Autowired(required = false) // 由于 yudao.tenant.enable 配置项，可以关闭多租户的功能，所以这里只能不强制注入
    private TenantProperties tenantProperties;

    @Resource
    private TenantMapper tenantMapper;

    @Resource
    private TenantPackageService tenantPackageService;
    @Resource
    @Lazy // 延迟，避免循环依赖报错
    private AdminUserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private MenuService menuService;
    @Resource
    private PermissionService permissionService;
    @Resource
    private TenantBalanceMapper tenantBalanceMapper;
    @Resource
    private TenantAgencyPackageService tenantAgencyPackageService;
    @Resource
    private AdminUserMapper userMapper;
    @Resource
    private TenantBalanceService balanceService;
    @Autowired
    private TenantBalanceService tenantBalanceService;

    @Override
    public List<Long> getTenantIdList() {
        List<TenantDO> tenants = tenantMapper.selectList();
        return CollectionUtils.convertList(tenants, TenantDO::getId);
    }

    @Override
    public void validTenant(Long id) {
        TenantDO tenant = getTenant(id);
        if (tenant == null) {
            throw exception(TENANT_NOT_EXISTS);
        }
        if (tenant.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) {
            throw exception(TENANT_DISABLE, tenant.getName());
        }
        if (DateUtils.isExpired(tenant.getExpireTime())) {
            throw exception(TENANT_EXPIRE, tenant.getName());
        }
    }

    @Override
    public PageResult<TenantDO> getSelfTenantPage(TenantPageReqVO pageVO) {
        Long tenantId = TenantContextHolder.getTenantId();
        pageVO.setParentId(tenantId);
        return tenantMapper.selectSelfPage(pageVO);
    }

    @Override
    public List<TenantDO> getChildrenTenant(Long id) {
        return tenantMapper.selectTenantByParentId(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TenantIgnore
    public void renewalTenant(TenantRenewalReqVO updateReqVO) {
        // 校验租户是否存在
        TenantDO targetTenant = getTenant(updateReqVO.getId());
        Long currentTenantId = TenantContextHolder.getTenantId();
        if (targetTenant == null) {
            throw exception(TENANT_NOT_EXISTS);
        }

        // 校验租户是否为代理类型
        if (targetTenant.getTenantType().equals(TenantEnum.AGENCY.getTenantType())) {
            throw exception(TENANT_IS_AGENCY);
        }

        TenantAgencyPackageDO tenantAgencyPackage = tenantAgencyPackageService.getTenantAgencyPackage(updateReqVO.getPackageId());

        TenantBalanceDO tenantBalance = tenantBalanceService.getTenantBalance(currentTenantId);

        AdminUserDO targetTenantUser = userService.getUserByTenantIdAndUserName(updateReqVO.getId(), targetTenant.getInitialUser());


        if (targetTenantUser == null) {
            throw exception(TENANT_USER_NOT_EXISTS);
        }

        if (tenantBalance.getBalance() < tenantAgencyPackage.getPrice()){
            throw exception(TENANT_BALANCE_NOT_ENOUGH);
        }

        if (balanceService.consumption(tenantAgencyPackage.getId(), targetTenant.getId(), updateReqVO.getRemark())) {
            log.info("代理: {} 续费租户:{} 成功,套餐 Id:{}", currentTenantId,targetTenant.getId(),updateReqVO.getPackageId());
        }

        if (targetTenant.getExpireTime().isBefore(LocalDateTime.now())){
            targetTenant.setExpireTime(LocalDateTime.now().plusDays(tenantAgencyPackage.getDays()));
            targetTenant.setStatus(CommonStatusEnum.ENABLE.getStatus());
            targetTenantUser.setCrawl((byte) 1);
        }else {
            targetTenant.setExpireTime(targetTenant.getExpireTime().plusDays(tenantAgencyPackage.getDays()));
        }

        if (tenantAgencyPackage.getAiClient()==1){
            if (targetTenant.getAiExpireTime().isBefore(LocalDateTime.now())){
                targetTenant.setAiExpireTime(LocalDateTime.now().plusDays(tenantAgencyPackage.getDays()));
                targetTenantUser.setAiReplay((byte) 1);
                targetTenantUser.setAiChat((byte) 1);
            }else {
                targetTenant.setAiExpireTime(targetTenant.getAiExpireTime().plusDays(tenantAgencyPackage.getDays()));
            }
        }

        if (tenantAgencyPackage.getBrotherClient() ==1 ){
            if (targetTenant.getBrotherExpireTime().isBefore(LocalDateTime.now())){
                targetTenant.setBrotherExpireTime(LocalDateTime.now().plusDays(tenantAgencyPackage.getDays()));
                targetTenantUser.setBigBrother((byte) 1);
            }else {
                targetTenant.setBrotherExpireTime(targetTenant.getBrotherExpireTime().plusDays(tenantAgencyPackage.getDays()));
            }
        }
        int updateInitialUserCount = userMapper.updateByIdWithRenwal(targetTenantUser);
        if (updateInitialUserCount <= 0) {
            throw exception(TENANT_UPDATE_INITIAL_USER_INFO_FAIL);
        }

        int updateTenantCount = tenantMapper.updateById(targetTenant);
        if (updateTenantCount <= 0) {
            throw exception(TENANT_RENEWAL_FAIL);
        }

    }

    @Override
    @DSTransactional // 多数据源，使用 @DSTransactional 保证本地事务，以及数据源的切换
    @DataPermission(enable = false) // 参见 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1154 说明
    public Long createTenant(TenantSaveReqVO createReqVO) {

        // 获取当前操作租户的ID（即创建者的租户ID）
        Long currentTenantId = TenantContextHolder.getTenantId();
        if (currentTenantId != 1){
            // 校验租户名称是否重复（null表示新增场景，无需排除当前ID）
            validTenantNameDuplicate(createReqVO.getName(), null);

            // 校验租户域名是否重复（null表示新增场景，无需排除当前ID）
            validTenantWebsiteDuplicate(createReqVO.getWebsite(), null);

            // 校验并获取租户套餐信息（确保套餐存在且未被禁用）
            TenantAgencyPackageDO tenantAgencyPackageDO = tenantAgencyPackageService.validTenantPackage(createReqVO.getPackageId());

            // 查询当前租户的详细信息
            TenantDO currentTenant = tenantMapper.selectById(currentTenantId);

            // 校验租户类型和层级权限：不允许创建代理类型租户，或当前租户级别为2的租户不允许创建
            if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType()) && currentTenant.getTenantLevel() == 2) {
                throw exception(TENANT_LEVEL_CANT_CREATE_AGENCY);
            }

            // 将请求参数转换为租户数据对象
            TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class);

            // 获取当前时间并计算租户过期时间
            String now = DateUtil.now();                    // 获取当前时间字符串
            DateTime dt = DateUtil.parse(now);              // 将时间字符串解析为DateTime对象
            LocalDateTime localDateTime = LocalDateTimeUtil.of(dt);  // 转换为LocalDateTime对象
            // 根据套餐天数计算过期时间：当前时间 + 套餐天数
            LocalDateTime offset = LocalDateTimeUtil.offset(localDateTime, tenantAgencyPackageDO.getDays(), ChronoUnit.DAYS);
            
            // 设置租户的基本过期时间
            tenant.setExpireTime(offset);
            // 设置租户的初始用户名（创建者）
            tenant.setInitialUser(createReqVO.getUsername());
            
            // 根据套餐配置设置特定功能的过期时间
            // 如果套餐包含"大哥客户端"功能，则设置大哥客户端的过期时间
            if (tenantAgencyPackageDO.getBrotherClient() == 1){
                tenant.setBrotherExpireTime(offset);
            }
            // 如果套餐包含"AI客户端"功能，则设置AI客户端的过期时间
            if (tenantAgencyPackageDO.getAiClient() == 1){
                tenant.setAiExpireTime(offset);
            }
            if(tenantAgencyPackageDO.getBrotherClient() == 2){}
            // 设置新租户的级别为当前租户级别+1（层级关系）
            if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType())){
                tenant.setTenantLevel(currentTenant.getTenantLevel() + 1);
            }
            // 设置新租户的父租户ID为当前租户ID（建立层级关系）
            tenant.setParentId(currentTenantId);

            if (tenant.getTenantType().equals(TenantEnum.AGENCY.getTenantType())) {
                tenant.setStatus(CommonStatusEnum.DISABLE.getStatus());
            }

            tenantMapper.insert(tenant);
            // 扣除开通费用，
            if (balanceService.consumption(createReqVO.getPackageId(), tenant.getId(), createReqVO.getRemark())) {
                log.info("代理: {} 开通租户:{} 成功,套餐 Id:{}", currentTenantId,tenant.getId(),createReqVO.getPackageId());
            }
            // 开通测试套餐扣除测试账号数
            if (tenantAgencyPackageDO.getPackageType().equals(PackageTypeEnum.TEST.getValue())){
                balanceService.reduceTestAccountNum(currentTenantId, createReqVO.getRemark());
            }
            if (!tenantAgencyPackageDO.getPackageType().equals(PackageTypeEnum.AGENCY.getValue())
                    && !tenantAgencyPackageDO.getPackageType().equals(PackageTypeEnum.TEST.getValue())) {
                balanceService.addTestAccountNum(currentTenantId, createReqVO.getRemark());
            }

            // 在新创建的租户上下文中执行管理员初始化操作
            TenantUtils.execute(tenant.getId(), () -> {
                // 创建租户的默认角色
                Long roleId = AgencyCreateRole(tenantAgencyPackageDO);

                // 创建租户的管理员用户，并分配角色
                Long userId = createUser(roleId, createReqVO);
                AdminUserDO user = userService.getUser(userId);
                if (tenantAgencyPackageDO.getHostslClient() == 1){
                    user.setCrawl((byte) 1);
                }
                if (tenantAgencyPackageDO.getBrotherClient() == 1){
                    user.setBigBrother((byte) 1);
                }
                if (tenantAgencyPackageDO.getAiClient() == 1){
                    user.setAiChat((byte) 1);
                }
                if (tenantAgencyPackageDO.getAiReplay() == 1){
                    user.setAiReplay((byte) 1);
                }
                if (tenantAgencyPackageDO.getWebAi() == 1){
                    user.setWebAi((byte) 1);
                }
                userMapper.updateById(user);
                // 将创建的用户设置为租户的联系人（管理员）
                tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId));
            });

            // 如果创建的是代理类型租户，则初始化其钱包
            if (tenant.getTenantType().equals("代理")) {
                // 创建租户钱包对象
                TenantBalanceDO tenantBalance = new TenantBalanceDO();
                tenantBalance.setId(tenant.getId()); // 钱包ID与租户ID一致
                tenantBalance.setBalance(0); // 初始余额设为0
                tenantBalance.setVersion(0); // 初始版本号设为0
                tenantBalance.setTestAccountNum(15);
                tenantBalanceMapper.insert(tenantBalance); // 插入钱包记录
            }

            // 返回新创建的租户ID
            return tenant.getId();
        }
        // 校验租户名称是否重复（null表示新增场景，无需排除当前ID）
        validTenantNameDuplicate(createReqVO.getName(), null);

        // 校验租户域名是否重复（null表示新增场景，无需排除当前ID）
        validTenantWebsiteDuplicate(createReqVO.getWebsite(), null);

        // 校验并获取租户套餐信息（确保套餐存在且未被禁用）
        TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId());

        // 查询当前租户的详细信息
        TenantDO currentTenant = tenantMapper.selectById(currentTenantId);

        // 校验租户类型和层级权限：不允许创建代理类型租户，或当前租户级别为2的租户不允许创建
        if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType()) && currentTenant.getTenantLevel() == 2) {
            throw exception(TENANT_LEVEL_CANT_CREATE_AGENCY);
        }

        // 将请求参数转换为租户数据对象
        TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class);

        // 设置新租户的级别为当前租户级别+1（层级关系）
        if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType())){
            tenant.setTenantLevel(currentTenant.getTenantLevel() + 1);
        }
        // 设置新租户的父租户ID为当前租户ID（建立层级关系）
        tenant.setParentId(currentTenantId);

        // 将新租户信息插入数据库
        tenantMapper.insert(tenant);

        // 在新创建的租户上下文中执行管理员初始化操作
        TenantUtils.execute(tenant.getId(), () -> {
            // 创建租户的默认角色
            Long roleId = createRole(tenantPackage);

            // 创建租户的管理员用户，并分配角色
            Long userId = createUser(roleId, createReqVO);

            // 将创建的用户设置为租户的联系人（管理员）
            tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId));
        });

        // 如果创建的是代理类型租户，则初始化其钱包
        if (tenant.getTenantType().equals("代理")) {
            // 创建租户钱包对象
            TenantBalanceDO tenantBalance = new TenantBalanceDO();
            tenantBalance.setId(tenant.getId()); // 钱包ID与租户ID一致
            tenantBalance.setBalance(0); // 初始余额设为0
            tenantBalance.setVersion(0); // 初始版本号设为0
            tenantBalance.setTestAccountNum(15);
            tenantBalanceMapper.insert(tenantBalance); // 插入钱包记录
        }

        // 返回新创建的租户ID
        return tenant.getId();
    }

    private Long createUser(Long roleId, TenantSaveReqVO createReqVO) {
        // 创建用户
        Long userId = userService.createUser(TenantConvert.INSTANCE.convert02(createReqVO));
        // 分配角色
        permissionService.assignUserRole(userId, singleton(roleId));
        return userId;
    }

    private Long createRole(TenantPackageDO tenantPackage) {
        // 创建角色
        RoleSaveReqVO reqVO = new RoleSaveReqVO();
        reqVO.setName(RoleCodeEnum.TENANT_ADMIN.getName()).setCode(RoleCodeEnum.TENANT_ADMIN.getCode())
                .setSort(0).setRemark("系统自动生成");
        Long roleId = roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType());
        // 分配权限
        permissionService.assignRoleMenu(roleId, tenantPackage.getMenuIds());
        return roleId;
    }

    private Long AgencyCreateRole(TenantAgencyPackageDO agencyPackageDO) {
        // 创建角色
        RoleSaveReqVO reqVO = new RoleSaveReqVO();
        reqVO.setName(RoleCodeEnum.TENANT_ADMIN.getName()).setCode(RoleCodeEnum.TENANT_ADMIN.getCode())
                .setSort(0).setRemark("系统自动生成");
        Long roleId = roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType());
        // 分配权限
        permissionService.assignRoleMenu(roleId, agencyPackageDO.getMenuIds());
        return roleId;
    }

    @Override
    @DSTransactional // 多数据源，使用 @DSTransactional 保证本地事务，以及数据源的切换
    public void updateTenant(TenantSaveReqVO updateReqVO) {
        // 校验存在
        TenantDO tenant = validateUpdateTenant(updateReqVO.getId());
        // 校验租户名称是否重复
        validTenantNameDuplicate(updateReqVO.getName(), updateReqVO.getId());
        // 校验租户域名是否重复
        validTenantWebsiteDuplicate(updateReqVO.getWebsite(), updateReqVO.getId());
        // 校验套餐被禁用

        if (updateReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType()) || tenant.getParentId() != 1) {
            TenantAgencyPackageDO tenantAgencyPackageDO = tenantAgencyPackageService.validTenantPackage(updateReqVO.getPackageId());
            // 更新租户
            TenantDO updateObj = BeanUtils.toBean(updateReqVO, TenantDO.class);
            tenantMapper.updateById(updateObj);
            // 如果套餐发生变化，则修改其角色的权限
            if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) {
                updateTenantRoleMenu(tenant.getId(), tenantAgencyPackageDO.getMenuIds());
            }
        }else {
            TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId());
            // 更新租户
            TenantDO updateObj = BeanUtils.toBean(updateReqVO, TenantDO.class);
            tenantMapper.updateById(updateObj);
            // 如果套餐发生变化，则修改其角色的权限
            if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) {
                updateTenantRoleMenu(tenant.getId(), tenantPackage.getMenuIds());
            }
        }

    }

    private void validTenantNameDuplicate(String name, Long id) {
        TenantDO tenant = tenantMapper.selectByName(name);
        if (tenant == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同名字的租户
        if (id == null) {
            throw exception(TENANT_NAME_DUPLICATE, name);
        }
        if (!tenant.getId().equals(id)) {
            throw exception(TENANT_NAME_DUPLICATE, name);
        }
    }

    private void validTenantWebsiteDuplicate(String website, Long id) {
        if (StrUtil.isEmpty(website)) {
            return;
        }
        TenantDO tenant = tenantMapper.selectByWebsite(website);
        if (tenant == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同名字的租户
        if (id == null) {
            throw exception(TENANT_WEBSITE_DUPLICATE, website);
        }
        if (!tenant.getId().equals(id)) {
            throw exception(TENANT_WEBSITE_DUPLICATE, website);
        }
    }

    @Override
    @DSTransactional
    public void updateTenantRoleMenu(Long tenantId, Set<Long> menuIds) {
        TenantUtils.execute(tenantId, () -> {
            // 获得所有角色
            List<RoleDO> roles = roleService.getRoleList();
            roles.forEach(role -> Assert.isTrue(tenantId.equals(role.getTenantId()), "角色({}/{}) 租户不匹配",
                    role.getId(), role.getTenantId(), tenantId)); // 兜底校验
            // 重新分配每个角色的权限
            roles.forEach(role -> {
                // 如果是租户管理员，重新分配其权限为租户套餐的权限
                if (Objects.equals(role.getCode(), RoleCodeEnum.TENANT_ADMIN.getCode())) {
                    permissionService.assignRoleMenu(role.getId(), menuIds);
                    log.info("[updateTenantRoleMenu][租户管理员({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), menuIds);
                    return;
                }
                // 如果是其他角色，则去掉超过套餐的权限
                Set<Long> roleMenuIds = permissionService.getRoleMenuListByRoleId(role.getId());
                roleMenuIds = CollUtil.intersectionDistinct(roleMenuIds, menuIds);
                permissionService.assignRoleMenu(role.getId(), roleMenuIds);
                log.info("[updateTenantRoleMenu][角色({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), roleMenuIds);
            });
        });
    }

    @Override
    public void deleteTenant(Long id) {
        // 校验存在
        validateUpdateTenant(id);
        // 删除
        tenantMapper.deleteById(id);
    }

    private TenantDO validateUpdateTenant(Long id) {
        TenantDO tenant = tenantMapper.selectById(id);
        if (tenant == null) {
            throw exception(TENANT_NOT_EXISTS);
        }
        // 内置租户，不允许删除
        if (isSystemTenant(tenant)) {
            throw exception(TENANT_CAN_NOT_UPDATE_SYSTEM);
        }
        return tenant;
    }

    @Override
    public TenantDO getTenant(Long id) {
        return tenantMapper.selectById(id);
    }

    @Override
    public PageResult<TenantDO> getTenantPage(TenantPageReqVO pageReqVO) {
        return tenantMapper.selectPage(pageReqVO);
    }

    @Override
    public TenantDO getTenantByName(String name) {
        return tenantMapper.selectByName(name);
    }

    @Override
    public TenantDO getTenantByWebsite(String website) {
        return tenantMapper.selectByWebsite(website);
    }

    @Override
    public Long getTenantCountByPackageId(Long packageId) {
        return tenantMapper.selectCountByPackageId(packageId);
    }

    @Override
    public List<TenantDO> getTenantListByPackageId(Long packageId) {
        return tenantMapper.selectListByPackageId(packageId);
    }

    @Override
    public List<TenantDO> getTenantListByStatus(Integer status) {
        return tenantMapper.selectListByStatus(status);
    }

    @Override
    public void handleTenantInfo(TenantInfoHandler handler) {
        // 如果禁用，则不执行逻辑
        if (isTenantDisable()) {
            return;
        }
        // 获得租户
        TenantDO tenant = getTenant(TenantContextHolder.getRequiredTenantId());
        // 执行处理器
        handler.handle(tenant);
    }

    @Override
    public void handleTenantMenu(TenantMenuHandler handler) {
        // 如果禁用，则不执行逻辑
        if (isTenantDisable()) {
            return;
        }
        // 获得租户，然后获得菜单
        TenantDO tenant = getTenant(TenantContextHolder.getRequiredTenantId());
        Set<Long> menuIds;
        if (isSystemTenant(tenant)) { // 系统租户，菜单是全量的
            menuIds = CollectionUtils.convertSet(menuService.getMenuList(), MenuDO::getId);
        } else {
            menuIds = tenantPackageService.getTenantPackage(tenant.getPackageId()).getMenuIds();
        }
        // 执行处理器
        handler.handle(menuIds);
    }

    private static boolean isSystemTenant(TenantDO tenant) {
        return Objects.equals(tenant.getPackageId(), TenantDO.PACKAGE_ID_SYSTEM);
    }

    private boolean isTenantDisable() {
        return tenantProperties == null || Boolean.FALSE.equals(tenantProperties.getEnable());
    }

}