package com.cf.imes.module.system.service.organ;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageParam;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.collection.CollectionUtils;
import com.cf.imes.framework.common.util.date.DateUtils;
import com.cf.imes.framework.common.util.date.LocalDateTimeUtils;
import com.cf.imes.framework.common.util.i18n.core.util.I18nUtils;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.common.util.pinyin.PinYinUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.mybatis.core.query.LambdaUpdateWrapperX;
import com.cf.imes.framework.organ.config.OrganProperties;
import com.cf.imes.framework.organ.core.aop.OrganIgnore;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.framework.organ.core.util.OrganUtils;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.system.api.organ.dto.OrgStatisticsIsLapseRespDTO;
import com.cf.imes.module.system.constants.permission.InternalRoleConstants;
import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganCreateProductPurchaseReqVO;
import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganPageReqVO;
import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganRespVO;
import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganSaveReqVO;
import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganSimpleRespVO;
import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganUpdateStatusReqVO;
import com.cf.imes.module.system.controller.admin.statistics.vo.ManageOrgTotalStatisticRespVO;
import com.cf.imes.module.system.controller.admin.statistics.vo.OrgStatusGroupStatisticsReqVO;
import com.cf.imes.module.system.controller.admin.systemconfig.vo.ProcessSchemeConfig;
import com.cf.imes.module.system.dal.dataobject.customplateno.CustomPlateNoSeqDO;
import com.cf.imes.module.system.dal.mysql.customplateno.CustomPlateNoSeqMapper;
import com.cf.imes.module.system.framework.jwt.config.JwtProperties;
import com.cf.imes.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import com.cf.imes.module.system.convert.organ.OrganConvert;
import com.cf.imes.module.system.dal.dataobject.dict.DictDataDO;
import com.cf.imes.module.system.dal.dataobject.lable.LabelDO;
import com.cf.imes.module.system.dal.dataobject.machine.MachineDO;
import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
import com.cf.imes.module.system.dal.dataobject.permission.MenuDO;
import com.cf.imes.module.system.dal.dataobject.permission.RoleDO;
import com.cf.imes.module.system.dal.dataobject.systemconfig.*;
import com.cf.imes.module.system.dal.dataobject.tokenconfig.TokenConfigDO;
import com.cf.imes.module.system.dal.mysql.dict.DictDataMapper;
import com.cf.imes.module.system.dal.mysql.label.LabelMapper;
import com.cf.imes.module.system.dal.mysql.machine.MachineMapper;
import com.cf.imes.module.system.dal.mysql.organ.OrganMapper;
import com.cf.imes.module.system.dal.mysql.systemconfig.*;
import com.cf.imes.module.system.dal.mysql.tokenconfig.TokenConfigMapper;
import com.cf.imes.module.system.enums.config.SystemConfigTypeEnum;
import com.cf.imes.module.system.enums.permission.RoleCodeEnum;
import com.cf.imes.module.system.framework.product.ProductProperties;
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
import com.cf.imes.module.system.service.lable.LabelService;
import com.cf.imes.module.system.service.organ.handler.OrganInfoHandler;
import com.cf.imes.module.system.service.organ.handler.OrganMenuHandler;
import com.cf.imes.module.system.service.permission.MenuService;
import com.cf.imes.module.system.service.permission.PermissionService;
import com.cf.imes.module.system.service.permission.RoleService;
import com.cf.imes.module.system.service.user.AdminUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.cf.imes.framework.common.constants.StatisticsConstants.DATELIST_FIELD_NAME;
import static com.cf.imes.framework.common.constants.StatisticsConstants.SERIES_FIELD_NAME;
import static com.cf.imes.framework.common.util.json.JsonUtils.parseArray;
import static com.cf.imes.framework.common.util.time.StatisticsChangeUtils.generateDateRangeAxis;
import static com.cf.imes.framework.common.util.time.StatisticsChangeUtils.getDateList;
import static com.cf.imes.module.system.dal.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;
import static com.cf.imes.module.system.service.tokenconfig.TokenConfigServiceImpl.generateBaseToken;
import static java.util.Collections.singleton;

/**
 * 组织 Service 实现类
 *
 * @author 晨丰科技
 */
@Service
@Validated
@Slf4j
public class OrganServiceImpl implements OrganService {

    @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
    @Autowired(required = false) // 由于 chenfeng.tenant.enable 配置项，可以关闭多组织的功能，所以这里只能不强制注入
    private OrganProperties organProperties;

    @Resource
    private OrganMapper organMapper;

    @Resource
    private TenantPackageService tenantPackageService;
    @Resource
    @Lazy // 延迟，避免循环依赖报错
    private AdminUserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private MenuService menuService;
    @Resource
    private PermissionService permissionService;

    @Value("${chenfeng.organ.use-data-code:imes_prod}")
    private String useDataCode;

    @Resource
    private TokenConfigMapper tokenConfigMapper;

    @Resource
    private JwtProperties jwtProperties;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private DictDataMapper dictDataMapper;

    @Resource
    private SystemConfigMapper systemConfigMapper;

    @Resource
    private SystemConfigFilterMapper systemConfigFilterMapper;

    @Resource
    private SystemConfigSchemeMapper systemConfigSchemeMapper;

    @Resource
    private SystemConfigSealedgeMapper systemConfigSealedgeMapper;

    @Resource
    private MachineMapper machineMapper;

    @Resource
    private LabelMapper labelMapper;

    @Resource
    private LabelService labelService;

    @Resource
    private PurchaseService purchaseService;

    @Resource
    private I18nUtils i18nUtils;

    @Resource
    private CustomPlateNoSeqMapper customPlateNoSeqMapper;

    @Resource
    private ProductProperties productProperties;

    @Override
    public List<Long> getOrganIdList() {
        List<OrganizationDO> organizationDOS = organMapper.selectList();
        return CollectionUtils.convertList(organizationDOS, OrganizationDO::getId);
    }

    @Override
    public OrganizationDO validOrgan(Long id) {
        OrganizationDO organizationDO = getOrgan(id);
        if (organizationDO == null) {
            throw new ServiceException(ORGAN_NOT_EXISTS);
        }
        if (organizationDO.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) {
            throw new ServiceException(ORGAN_DISABLE, organizationDO.getName());
        }
        if (DateUtils.isExpired(organizationDO.getExpireTime())) {
            throw new ServiceException(ORGAN_EXPIRE, organizationDO.getName());
        }
        return organizationDO;
    }

    @Override
    public List<OrganSimpleRespVO> getSimpleOrganList(String name) {
        List<OrganizationDO> organizationDOS = organMapper.selectList(new LambdaQueryWrapperX<OrganizationDO>()
                .likeIfPresent(OrganizationDO::getName, name)
                .select(OrganizationDO::getId, OrganizationDO::getName));
       return BeanUtils.toBean(organizationDOS, OrganSimpleRespVO.class);
    }

    @Override
    @DSTransactional // 多数据源，使用 @DSTransactional 保证本地事务，以及数据源的切换
    public Long createOrgan(OrganSaveReqVO createReqVO) {
        // 校验组织名称是否重复
        validTenantNameDuplicate(createReqVO.getName(), null);
        // 校验组织域名是否重复
        validTenantWebsiteDuplicate(createReqVO.getWebsite(), null);
        // 校验组织手机号是否重复
        validContactMobileDuplicate(createReqVO.getOrgAdminMobile(),null);

        // 创建组织
        OrganizationDO tenant = BeanUtils.toBean(createReqVO, OrganizationDO.class);
        // 管理员姓名/手机 适配 原联系人
        tenant.setContactName(createReqVO.getOrgAdminName());
        tenant.setContactMobile(createReqVO.getOrgAdminMobile());
        String pinyinFull = PinYinUtils.convertToPinyin(tenant.getName());
        if(CharSequenceUtil.isNotBlank(pinyinFull)) {
            pinyinFull = pinyinFull.replace(" ", "");
        }
        tenant.setPinyinFull(pinyinFull);
        tenant.setLarge(createReqVO.getLarge() == null ? Boolean.FALSE : createReqVO.getLarge());
        tenant.setPinyinInitial(PinYinUtils.convertFirstChar(tenant.getName()));
        //todo 未来还需要判断是否大客户，大客户有自己dataCode
        tenant.setDataSourceCode(useDataCode);
        // 过期时间设置为那一日的23：59：59
        tenant.setExpireTime(LocalDateTime.of(createReqVO.getExpireTime(), LocalTime.of(23, 59, 59)));

        organMapper.insert(tenant);
        Long organId = tenant.getId();
        // 创建组织的管理员
        // 1、创建用户，并分配角色
        Long userId = createUser(InternalRoleConstants.ORGAN_ADMIN_ROLE_ID, createReqVO, organId);
        // 2、修改组织的管理员
        organMapper.update(new LambdaUpdateWrapper<OrganizationDO>()
                .eq(OrganizationDO::getId, organId)
                .set(OrganizationDO::getContactUserId, userId));

        // 复制系统配置里的相关配置
        copySystemConfig(organId);
        // 复制默认标签
        labelService.copyInitalLabel(organId);

        // 创建产品购买记录
        List<OrganCreateProductPurchaseReqVO> productPurchaseReqVOS = createReqVO.getProductPurchaseReqVOS();
        // 根据productId去重，初次订购每个产品只能有一种订购
        productPurchaseReqVOS = productPurchaseReqVOS.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(OrganCreateProductPurchaseReqVO::getProductId))), ArrayList::new));
        purchaseService.createOrgInitProductPurchaseRecord(organId, productPurchaseReqVOS);

        return tenant.getId();
    }

    private Long createUser(Long roleId, OrganSaveReqVO createReqVO, Long organId) {
        // 创建用户
        UserSaveReqVO reqVO = OrganConvert.INSTANCE.convert02(createReqVO);
        reqVO.setOrganId(organId);
        Long userId = userService.createUser(reqVO);
        // 分配角色
        permissionService.assignUserRole(userId, singleton(roleId), organId);
        return userId;
    }

    @Override
    @DSTransactional // 多数据源，使用 @DSTransactional 保证本地事务，以及数据源的切换
    public void updateOrgan(OrganSaveReqVO updateReqVO) {
        Long organId = updateReqVO.getId();
        // 校验存在
        OrganizationDO tenant = validateUpdateTenant(organId);
        // 校验组织名称是否重复
        validTenantNameDuplicate(updateReqVO.getName(), organId);
        // 校验组织域名是否重复
        validTenantWebsiteDuplicate(updateReqVO.getWebsite(), organId);
        // 校验组织手机号是否重复
        String currentOrgAdminMobile = updateReqVO.getOrgAdminMobile();
        validContactMobileDuplicate(currentOrgAdminMobile, organId);
        // 不允许禁用自身组织
        checkCfOrgWhenOperate(organId);

        if (!Objects.equals(tenant.getName(), updateReqVO.getName())) {
            String pinyinFull = PinYinUtils.convertToPinyin(tenant.getName());
            if (CharSequenceUtil.isNotBlank(pinyinFull)) {
                pinyinFull = pinyinFull.replace(" ", "");
            }
            tenant.setPinyinFull(pinyinFull);
            tenant.setPinyinInitial(PinYinUtils.convertFirstChar(tenant.getName()));
        }


        String mobileChange = null;
        String nicknameChange = null;
        // 手机号更新
        String contactMobile = tenant.getContactMobile();
        if (ObjectUtil.notEqual(contactMobile, currentOrgAdminMobile)) {
            // 同步更新 token 管理的 token
            List<TokenConfigDO> tokenConfigDOS = tokenConfigMapper.selectConfigByOrganId(organId);
            if (CollUtil.isNotEmpty(tokenConfigDOS)) {
                tokenConfigDOS.forEach(f -> f.setAppToken(generateBaseToken(organId, currentOrgAdminMobile, f.getAppType(), jwtProperties.getSecret())));
                tokenConfigMapper.updateBatch(tokenConfigDOS);
            }
            mobileChange = currentOrgAdminMobile;
        }
        // 昵称更新
        if (ObjectUtil.notEqual(tenant.getContactName(), updateReqVO.getOrgAdminName())) {
            nicknameChange = updateReqVO.getOrgAdminName();
        }
        // 同步到管理员账号
        userService.syncOrgAdminToUser(tenant.getContactUserId(), mobileChange, nicknameChange);

        // 更新组织
        OrganizationDO updateObj = BeanUtils.toBean(updateReqVO, OrganizationDO.class);
        updateObj.setContactMobile(mobileChange);
        updateObj.setContactName(nicknameChange);
        // 过期时间设置为那一日的23：59：59
        updateObj.setExpireTime(LocalDateTime.of(updateReqVO.getExpireTime(), LocalTime.of(23, 59, 59)));
        organMapper.updateById(updateObj);

        // 更新产品购买记录
        purchaseService.updateOrgInitProductPurchaseRecord(organId, updateReqVO.getProductPurchaseReqVOS());

        if (CommonStatusEnum.DISABLE.getStatus().equals(updateReqVO.getStatus())) {
            // 移除机构下用户的token
            scanAndCompareDeptAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), organId);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrganStatus(OrganUpdateStatusReqVO updateReqVO) {
        Long organId = updateReqVO.getId();
        Integer status = updateReqVO.getStatus();
        // 校验存在
        OrganizationDO tenant = validateUpdateTenant(organId);
        // 不允许禁用自身组织
        checkCfOrgWhenOperate(organId);
        // 更新状态
        OrganizationDO updateObj = new OrganizationDO();
        updateObj.setId(organId);
        updateObj.setStatus(status);
        organMapper.updateById(updateObj);

        if (CommonStatusEnum.DISABLE.getStatus().equals(status)) {
            // 移除机构下用户的token
            scanAndCompareDeptAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), organId);
        }
    }

    private void validTenantNameDuplicate(String name, Long id) {
        OrganizationDO tenant = organMapper.selectByName(name);
        if (tenant == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同名字的组织
        if (id == null) {
            throw new ServiceException(ORGAN_NAME_DUPLICATE, name);
        }
        if (!tenant.getId().equals(id)) {
            throw new ServiceException(ORGAN_NAME_DUPLICATE, name);
        }
    }

    private void validTenantWebsiteDuplicate(String website, Long id) {
        if (CharSequenceUtil.isEmpty(website)) {
            return;
        }
        OrganizationDO tenant = organMapper.selectByWebsite(website);
        if (tenant == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同名字的组织
        if (id == null) {
            throw new ServiceException(ORGAN_WEBSITE_DUPLICATE, website);
        }
        if (!tenant.getId().equals(id)) {
            throw new ServiceException(ORGAN_WEBSITE_DUPLICATE, website);
        }
    }


    private void validContactMobileDuplicate(String contactMobile,Long organId) {

        List<OrganizationDO> organizationDOS = organMapper.selectByContactMobile(contactMobile,organId);


        if(CollUtil.isNotEmpty(organizationDOS)){
            throw new ServiceException(ORGAN_CONTACTMOBILE_DUPLICATE,contactMobile);
        }
    }




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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrgan(Long id) {
        // 校验存在
        validateUpdateTenant(id);
        // 校验机构内用户操作
        checkCurrentWhenOperate(id);
        // 删除
        organMapper.deleteById(id);
        // 删除关联的用户
        userService.deleteOrgUsers(id);
        // 移除机构下用户的token
        scanAndCompareDeptAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), id);
    }

    /**
     * 轮训redis token，移除对应机构下的用户的token
     *
     * @param keyPattern
     * @param organId
     */
    private void scanAndCompareDeptAndDelToken(String keyPattern, Long organId) {
        // 根据keyPattern scan匹配的redis key
        List<String> matchKeys = new ArrayList<>();
        Cursor<String> cursor = stringRedisTemplate.scan(ScanOptions.scanOptions().match(keyPattern).count(200).build());
        while (cursor.hasNext()) {
            matchKeys.add(cursor.next());
        }
        cursor.close();
        if (CollUtil.isNotEmpty(matchKeys)) {
            for (String key : matchKeys) {
                // 获取key下的用户信息
                OAuth2AccessTokenDO oAuth2AccessTokenDO = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), OAuth2AccessTokenDO.class);
                if (ObjectUtil.equal(organId, oAuth2AccessTokenDO.getOrganId())) {
                    // 用户id匹配上了删除redis中的token缓存
                    stringRedisTemplate.delete(key);
                    return;
                }
            }
        }
    }

    /**
     * 不允许删除自身
     */
    private void checkCurrentWhenOperate(Long organId) {
        if (ObjectUtil.equal(organId, SecurityFrameworkUtils.getUserOrganId())) {
            throw new ServiceException(ORGAN_USER_OPER_NOT_ALLOW);
        }
    }

    /**
     * 不允许禁用自身
     */
    private void checkCfOrgWhenOperate(Long organId) {
        if (ObjectUtil.equal(organId, SecurityFrameworkUtils.CF_ORGANID)) {
            throw new ServiceException(ORGAN_USER_OPER_NOT_ALLOW);
        }
    }

    private OrganizationDO validateUpdateTenant(Long id) {
        OrganizationDO tenant = organMapper.selectById(id);
        if (tenant == null) {
            throw new ServiceException(ORGAN_NOT_EXISTS);
        }
        // 内置组织，不允许删除
        /*if (isSystemTenant(tenant)) {
            throw new ServiceException(ORGAN_CAN_NOT_UPDATE_SYSTEM);
        }*/
        return tenant;
    }

    @Override
    public OrganizationDO getOrgan(Long id) {
        return organMapper.selectById(id);
    }

    @Override
    public OrganizationDO getOrganWithDeleted(Long id) {
        return organMapper.selectByIdWithDeleted(id);
    }

    @Override
    public PageResult<OrganizationDO> getOrganPage(OrganPageReqVO pageReqVO) {
        pageReqVO.setExpireTime(LocalDateTimeUtils.generateTimeSection(pageReqVO.getExpireTime()));
        if(CharSequenceUtil.isNotBlank(pageReqVO.getName())) {
            pageReqVO.setPyFirstChar(PinYinUtils.convertFirstChar(pageReqVO.getName()));
            pageReqVO.setPyAll(PinYinUtils.convertToPinyin(pageReqVO.getName()).replace(" ", ""));
        } else {
            // 避免name为空外部传入拼音查询字段
            pageReqVO.setPyFirstChar(null);
            pageReqVO.setPyAll(null);
        }

        LocalDateTime[] endTime = pageReqVO.getEndTime();
        if ((ObjectUtil.isNotNull(endTime) && endTime.length == 2) ||
                ObjectUtil.isNotNull(pageReqVO.getProductName()) ||
                ObjectUtil.isNotNull(pageReqVO.getPrice())) {
            // 产品相关条件非空的情况下走带特定方法
            pageReqVO.setEndTime(LocalDateTimeUtils.generateTimeSection(endTime));

            PageDTO<OrganizationDO> page = new PageDTO<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
            IPage<OrganizationDO> organizationDOIPage = organMapper.selectPageWithProductExpire(page, pageReqVO);
            return new PageResult<>(organizationDOIPage.getRecords(), organizationDOIPage.getTotal());
        } else {
            return organMapper.selectPage(pageReqVO);
        }
    }

    @Override
    public OrganizationDO getOrganByName(String name) {
        return organMapper.selectByName(name);
    }

    @Override
    public OrganizationDO getOrganByWebsite(String website) {
        return organMapper.selectByWebsite(website);
    }

    @Override
    public Long getOrganCountByPackageId(Long packageId) {
        return organMapper.selectCountByPackageId(packageId);
    }

    @Override
    public List<OrganizationDO> getOrganListByPackageId(Long packageId) {
        return organMapper.selectListByPackageId(packageId);
    }

    @Override
    public void handleOrganInfo(OrganInfoHandler handler,Long organId) {
        // 如果禁用，则不执行逻辑
        if (isTenantDisable()) {
            return;
        }
        // 获得组织
        OrganizationDO tenant = getOrgan(ObjectUtil.isNotNull(organId) ? organId : OrganContextHolder.getRequiredOrganId());
        // 执行处理器
        handler.handle(tenant);
    }

    @Override
    public void handleOrganMenu(OrganMenuHandler handler) {
        // 如果禁用，则不执行逻辑
        if (isTenantDisable()) {
            return;
        }
        // 获得组织，然后获得菜单
        OrganizationDO tenant = getOrgan(OrganContextHolder.getRequiredOrganId());
        Set<Long> menuIds;

        if (isSystemTenant(tenant) || (SecurityFrameworkUtils.isCfOrg() && SecurityFrameworkUtils.isManageEndPoint())) { // 系统组织，菜单是全量的
            menuIds = CollectionUtils.convertSet(menuService.getMenuList(), MenuDO::getId);
        } else {
            menuIds = tenantPackageService.getTenantPackage(productProperties.getImesTenantPackage()).getMenuIds();
        }
        // 执行处理器
        handler.handle(menuIds);
    }

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

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

    @Override
    @OrganIgnore
    public ManageOrgTotalStatisticRespVO getOrgTotal() {
        ManageOrgTotalStatisticRespVO respVO = new ManageOrgTotalStatisticRespVO();

        LocalDate now = LocalDate.now();
        LocalDateTime todayStart = LocalDateTime.of(now, LocalTime.MIDNIGHT);
        LocalDateTime todayEnd = LocalDateTime.of(now, LocalTime.of(23, 59, 59));
        // 组织总数
        respVO.setOrgTotal(organMapper.selectOrgCount());
        // 当日新增数
        respVO.setOrgAdd(organMapper.selectOrgCountAdd(todayStart, todayEnd));
        // 当日状态-删除
        respVO.setOrgDel(organMapper.selectOrgCountDel(todayStart, todayEnd));
        // 当日沉寂数 (组织中所有用户30天未登录)
        // 获得30天前的时间，赋值时间为0：00：00
        Date date = DateUtil.offsetDay(new Date(), -30);
        respVO.setOrgSilent(organMapper.selectOrgSilentCount(DateUtil.beginOfDay(date).toLocalDateTime()));
        return respVO;
    }

    @Override
    @OrganIgnore
    public PageResult<OrganRespVO> getOrgAboutExpire(PageParam param) {
        IPage<OrganizationDO> organPage = organMapper.selectOrgCountExpire(param);
        return new PageResult<>(BeanUtils.toBean(organPage.getRecords(), OrganRespVO.class), organPage.getTotal());
    }

    @Override
    @OrganIgnore
    public PageResult<OrganRespVO> getOrgExpired(PageParam param) {
        IPage<OrganizationDO> organPage = organMapper.selectOrgCountExpired(param);
        return new PageResult<>(BeanUtils.toBean(organPage.getRecords(), OrganRespVO.class), organPage.getTotal());
    }

    /**
     * 复制系统配置
     *
     * @param organId
     */
    private void copySystemConfig(Long organId) {

        List<DictDataDO> dictDataDOS = dictDataMapper.selectListByStatusAndDictType(CommonStatusEnum.ENABLE.getStatus(), "copy_data_organ");
        if(CollUtil.isEmpty(dictDataDOS)){
            return;
        }

        String value = dictDataDOS.get(0).getValue();

        Long copyOrganId = Long.valueOf(value);


        // 自定义板编号
        List<SystemConfigDO> systemConfigDOS = systemConfigMapper.selectList(new LambdaQueryWrapperX<SystemConfigDO>()
                .eq(SystemConfigDO::getType, SystemConfigTypeEnum.CUSTOM_PLATE_NO.getType())
                .eq(SystemConfigDO::getOrganId, copyOrganId)
                .eq(SystemConfigDO::getDeleted, false));

        if(CollUtil.isNotEmpty(systemConfigDOS)){
            Optional<SystemConfigDO> configDO = systemConfigDOS.stream().max(Comparator.comparing(SystemConfigDO::getVersion));
            if (configDO.isPresent()) {
                SystemConfigDO systemConfigDO = configDO.get();
                systemConfigMapper.insert(SystemConfigDO.builder()
                        .name(systemConfigDO.getName())
                        .status(systemConfigDO.getStatus())
                        .sort(systemConfigDO.getSort())
                        .type(systemConfigDO.getType())
                        .setting(systemConfigDO.getSetting())
                        .organId(organId)
                        .build());

                // 初始化组织自定义板编号序列
                CustomPlateNoSeqDO customPlateNoSeqDO = new CustomPlateNoSeqDO();
                customPlateNoSeqDO.setOrganId(organId);
                customPlateNoSeqMapper.insert(customPlateNoSeqDO);
            }
        }


        // 板件筛选
        List<SystemConfigFilterDO> systemConfigFilterDOS = systemConfigFilterMapper.selectList(new LambdaQueryWrapperX<SystemConfigFilterDO>()
                .eq(SystemConfigFilterDO::getOrganId, copyOrganId)
                .eq(SystemConfigFilterDO::getDeleted, false)
                .eq(SystemConfigFilterDO::getType, SystemConfigTypeEnum.INTELLIGENT_BRANCH.getType()));
        if(CollUtil.isNotEmpty(systemConfigFilterDOS)){
            systemConfigFilterDOS.forEach(f->{
                f.setId(null);
                f.setOrganId(organId);
                f.setCreateTime(null);
                f.setCreator(null);
                f.setUpdateTime(null);
                f.setUpdater(null);
            });

            systemConfigFilterMapper.insertBatch(systemConfigFilterDOS);
        }


        // 封边条对应
        List<SystemConfigSealedgeDO> systemConfigSealedgeDOS = systemConfigSealedgeMapper.selectList(new LambdaQueryWrapperX<SystemConfigSealedgeDO>()
                .eq(SystemConfigSealedgeDO::getOrganId, copyOrganId)
                .eq(SystemConfigSealedgeDO::getDeleted, false)
                .eq(SystemConfigSealedgeDO::getType, SystemConfigTypeEnum.SEALEDGE.getType()));
        if(CollUtil.isNotEmpty(systemConfigSealedgeDOS)){
            systemConfigSealedgeDOS.forEach(f->{
                f.setId(null);
                f.setOrganId(organId);
                f.setCreateTime(null);
                f.setCreator(null);
                f.setUpdateTime(null);
                f.setUpdater(null);
            });

            systemConfigSealedgeMapper.insertBatch(systemConfigSealedgeDOS);
        }

    }



    // 复制加工方案组以及里面的机台信息以及标签的配置信息
    private void copyConfigSchemeMachineAndLabel(Long copyOrganId,Long organId){

        List<SystemConfigSchemeDO> systemConfigSchemeDOS = systemConfigSchemeMapper.selectList(new LambdaQueryWrapperX<SystemConfigSchemeDO>()
                .eq(SystemConfigSchemeDO::getOrganId, copyOrganId)
                .eq(SystemConfigSchemeDO::getDeleted, false)
                .eq(SystemConfigSchemeDO::getType, SystemConfigTypeEnum.PROCESS_SCHEME.getType()));


        if(CollUtil.isNotEmpty(systemConfigSchemeDOS)){

            // 加工方案组的配置信息
            List<ProcessSchemeConfig> processSchemeConfigs = new ArrayList<>();

            systemConfigSchemeDOS.forEach(f->{
                f.setId(null);
                f.setOrganId(organId);
                f.setCreateTime(null);
                f.setCreator(null);
                f.setUpdateTime(null);
                f.setUpdater(null);

                try {
                    processSchemeConfigs.addAll(parseArray(f.getSetting(), ProcessSchemeConfig.class));
                } catch (Exception e) {
                    log.error("加工方案组复制数据异常"+e.getMessage());
                }
            });


            List<String> machineIds = processSchemeConfigs.stream().map(ProcessSchemeConfig::getAnalyzer).distinct().toList();
            List<MachineDO> machineDOS = machineMapper.selectByIds(machineIds);
            if(CollUtil.isNotEmpty(machineDOS)){
                machineDOS.forEach(f->{
                    f.setId(null);
                    f.setOrganId(organId);
                    f.setCreateTime(null);
                    f.setCreator(null);
                    f.setUpdateTime(null);
                    f.setUpdater(null);
                });


                List<Long> labelIds = machineDOS.stream().map(MachineDO::getLabelId).distinct().toList();
                List<LabelDO> labelDOS = labelMapper.selectByIds(labelIds);
                if(CollUtil.isNotEmpty(labelDOS)){
                    labelDOS.forEach(f->{
                        f.setId(null);
                        f.setOrganId(organId);
                        f.setCreateTime(null);
                        f.setCreator(null);
                        f.setUpdateTime(null);
                        f.setUpdater(null);
                    });

                    labelMapper.insertBatch(labelDOS);
                }

                machineMapper.insertBatch(machineDOS);
            }

            systemConfigSchemeMapper.insertBatch(systemConfigSchemeDOS);
        }
    }

    @Override
    @OrganIgnore
    public Map<String, Object> getOrgStatusGroupStatistics(OrgStatusGroupStatisticsReqVO reqVO) {

        Map<String, Object> resultMap = new LinkedHashMap<>();

        // 所有的日期集合
        List<String> dateList = getDateList(reqVO);

        reqVO.setCreateTimeForQry(LocalDateTimeUtils.generateTimeSection(reqVO.getCreateTime()));
        // 组织有效数量
        Map<String, List<OrgStatisticsIsLapseRespDTO>> orderNotLapseRespMap = organMapper.selectOrgCountAddByOrderDate(reqVO).stream()
                .sorted(Comparator.naturalOrder())
                .collect(Collectors.groupingBy(OrgStatisticsIsLapseRespDTO::getDate, LinkedHashMap::new, Collectors.toList()));

        // 组织无效数量
        Map<String, List<OrgStatisticsIsLapseRespDTO>> orderLapseRespMap = organMapper.selectOrgCountLapseByOrderDate(reqVO).stream()
                .sorted(Comparator.naturalOrder())
                .collect(Collectors.groupingBy(OrgStatisticsIsLapseRespDTO::getDate, LinkedHashMap::new, Collectors.toList()));

        List<Map<String, Object>> series = new ArrayList<>();
        Map<String, Object> addSeriesItem = new HashMap<>();
        Map<String, Object> deleteSeriesItem = new HashMap<>();
        int[] addCountArr = new int[dateList.size()];
        int[] deleteCountArr = new int[dateList.size()];
        // 遍历时间跨度列表，匹配数量存入数组，没有补0存入数组
        for (int i = 0; i < dateList.size(); i++) {
            String dateStr = dateList.get(i);
            // 组织有效数量
            Integer orderNotLapseCount = Optional.ofNullable(orderNotLapseRespMap.get(dateStr))
                    .map(list -> list.stream().findFirst().orElse(new OrgStatisticsIsLapseRespDTO()))
                    .map(OrgStatisticsIsLapseRespDTO::getOrgCount)
                    .orElse(0);
            addCountArr[i] = orderNotLapseCount;


            // 组织无效数量
            Integer orderLapseCount = Optional.ofNullable(orderLapseRespMap.get(dateStr))
                    .map(list -> list.stream().findFirst().orElse(new OrgStatisticsIsLapseRespDTO()))
                    .map(OrgStatisticsIsLapseRespDTO::getOrgCount)
                    .orElse(0);
            deleteCountArr[i] = orderLapseCount;
        }
        addSeriesItem.put("data", addCountArr);
        addSeriesItem.put("name", i18nUtils.getMessage("statistics.series.name.add"));
        deleteSeriesItem.put("data", deleteCountArr);
        deleteSeriesItem.put("name", i18nUtils.getMessage("statistics.series.name.del"));
        series.add(addSeriesItem);
        series.add(deleteSeriesItem);

        // x轴时间区间字符串
        resultMap.put(DATELIST_FIELD_NAME, dateList.stream().map(date -> generateDateRangeAxis(date, reqVO.getUnit())).toList());
        // 类别：类别：单量数组
        resultMap.put(SERIES_FIELD_NAME, series);

        return resultMap;
    }

    @Override
    public void syncUserToOrgAdmin(Long id, String contactMobile, String contactName) {
        if (StringUtils.isAllEmpty(contactMobile, contactName)) {
            return;
        }
        organMapper.update(new LambdaUpdateWrapperX<OrganizationDO>()
                .setIfPresent(OrganizationDO::getContactMobile, contactMobile)
                .setIfPresent(OrganizationDO::getContactName, contactName)
                .eq(OrganizationDO::getId, id)
        );
    }

    @Override
    public Long getOrganAdmin(Long id) {
        OrganizationDO organizationDO = validOrgan(id);
        return organizationDO.getContactUserId();
    }
}
