package jnpf.certificate.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import jnpf.authority.utils.PermissionsApplicableEnums;
import jnpf.authority.utils.PermissionsApplicableObject;
import jnpf.authority.utils.PermissionsUtils;
import jnpf.base.ActionResult;
import jnpf.certificate.helper.NoticeHelper;
import jnpf.certificate.helper.OrganizationHelper;
import jnpf.certificate.mapper.CertificateInstanceMapper;
import jnpf.certificate.model.CertificateAppReminderRecord;
import jnpf.certificate.service.CertificateAppReminderService;
import jnpf.certificate.util.SubjectNameUtils;
import jnpf.model.certificate.po.CertificateInstanceEntity;
import jnpf.model.certificate.req.app.CertificateAppBatchRemindReq;
import jnpf.model.certificate.req.app.CertificateAppSingleRemindReq;
import jnpf.model.warningnotice.enums.CertificateTypeEnum;
import jnpf.permission.V2UserApi;
import jnpf.permission.vo.v2.organzie.OrganizeBaseInfoVO;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.permission.vo.v2.user.UserBoundInfoVO;
import jnpf.storecertificatephoto.helper.StoreCertificatePhotoHelper;
import jnpf.util.ServiceException;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.MutableTriple;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static jnpf.certificate.helper.NoticeHelper.URL_CERTIFICATE;

/**
 * App端证照提醒服务实现。
 */
@Service
@Slf4j
public class CertificateAppReminderServiceImpl implements CertificateAppReminderService {

    private static final int STATUS_MISSING = 1;
    private static final int STATUS_EXPIRED = 2;
    private static final int STATUS_NEAR_EXPIRE = 3;
    private static final int STATUS_NORMAL = 4;

    private static final int SUBJECT_TYPE_EMPLOYEE = 1;
    private static final int SUBJECT_TYPE_ORGANIZATION = 2;
    private static final int SUBJECT_TYPE_STORE = 3;

    @Autowired
    private CertificateInstanceMapper certificateInstanceMapper;
    @Autowired
    private V2UserApi v2UserApi;
    @Autowired
    private OrganizationHelper organizationHelper;
    @Autowired
    private PermissionsUtils permissionsUtils;
    @Autowired
    private NoticeHelper noticeHelper;
    @Autowired
    private StoreCertificatePhotoHelper storeCertificatePhotoHelper;
    @Autowired
    private ThreadPoolTaskExecutor commonExecutor;

    /**
     * 一键提醒。
     * 健康证提醒员工本人，非健康证提醒组织负责人。
     */
    @Override
    public void batchRemind(CertificateAppBatchRemindReq req) {
        log.error("batchRemind req:{}",req);
        ServiceException.notNull(req, "请求参数不能为空");
        Integer subjectType = req.getSubjectType();
        ServiceException.isTrue(subjectType != null && subjectType >= SUBJECT_TYPE_EMPLOYEE && subjectType <= SUBJECT_TYPE_STORE,
                "主体类型不合法");

        // 构建查询的subjectType列表，subjectType=2时同时查3
        List<Integer> subjectTypes = new ArrayList<>();
        subjectTypes.add(subjectType);
        if (Integer.valueOf(SUBJECT_TYPE_ORGANIZATION).equals(subjectType)) {
            subjectTypes.add(SUBJECT_TYPE_STORE);
        }
        // 查询非正常状态的证照实例
        List<Integer> statuses = Arrays.asList(STATUS_MISSING, STATUS_EXPIRED, STATUS_NEAR_EXPIRE);

        List<CertificateInstanceEntity> records= null;
        List<String> userIds = buildQueryUserIds(req.getOrgId());
        if(Objects.nonNull(userIds) && userIds.isEmpty()){//没查到数据，返回
            return;
        }
        if(req.getSubjectType() == SUBJECT_TYPE_EMPLOYEE){
            records = certificateInstanceMapper.selectBySubjectTypesAndStatusesFilterUser(subjectTypes, statuses,userIds);
        }else{
            records = certificateInstanceMapper.selectBySubjectTypesAndStatusesFilterOrganization(subjectTypes, statuses,req.getOrgId());
        }

        if (CollUtil.isEmpty(records)) {
            return;
        }

        String tenantId = UserProvider.getUser().getTenantId();
        String remindUserName = StrUtil.blankToDefault(StrUtil.trim(UserProvider.getUser().getUserName()), "系统");

        // 按是否健康证分组，批量解析接收人
        Map<Boolean, List<CertificateInstanceEntity>> grouped = records.stream()
                .collect(Collectors.partitioningBy(r -> isHealthCertificate(r.getCertificateType())));

        // 健康证：接收人就是员工本人(subjectId)
        Map<String, String> healthReceiverMap = resolveHealthReceivers(grouped.getOrDefault(true, Collections.emptyList()));
        // 非健康证：接收人是组织负责人
        MutableTriple<Map<String,String>,Map<String,String>,Map<String,String>>
        orgReceiversAndOrgNamesAndTemplateNames = buildOrgReceiversAndOrgNamesAndTemplateNames(grouped.getOrDefault(false, Collections.emptyList()));

        Map<String,String> orgReceivers = orgReceiversAndOrgNamesAndTemplateNames.getLeft();
        Map<String,String> orgNames = orgReceiversAndOrgNamesAndTemplateNames.getMiddle();
        Map<String,String> templateNames = orgReceiversAndOrgNamesAndTemplateNames.getRight();

        List<CertificateInstanceEntity> finalRecords = records;
        commonExecutor.execute(() -> sendNotices(finalRecords, healthReceiverMap, orgReceivers, orgNames, templateNames, tenantId, remindUserName));
    }

    private List<String> buildQueryUserIds(String orgId) {
        if(StringUtil.isBlank(orgId)){
            return null;
        }
        Map<String,List<String>> userIdsByOrgIds = organizationHelper.buildUserIdsByOrgIds(List.of(orgId),false,null);
        if(CollUtil.isEmpty(userIdsByOrgIds)){
            return Collections.emptyList();
        }
        List<String> userIds = userIdsByOrgIds.get(orgId);
        if(CollectionUtil.isEmpty(userIds)){
            return Collections.emptyList();
        }
        return userIds;
    }

    private void sendNotices(List<CertificateInstanceEntity> records,
                             Map<String, String> healthReceiverMap,
                             Map<String,String> orgReceivers,
                             Map<String,String> orgNames,
                             Map<String,String> templateNames,
                             String tenantId,
                             String remindUserName){
        for (CertificateInstanceEntity record : records) {
            String receiverUserId = isHealthCertificate(record.getCertificateType())
                    ? healthReceiverMap.get(StrUtil.trim(record.getSubjectId()))
                    : orgReceivers.get(StrUtil.trim(record.getSubjectId()));
            if (StrUtil.isBlank(receiverUserId)) {
                continue;
            }
            String subjectId = record.getSubjectId();
            String orgName = orgNames.get(subjectId);
            String templateName = null;

            String templateId = record.getTemplateId();
            if(StringUtil.isNotBlank(templateId)){
                templateName = templateNames.get(templateId);
            }
            sendNotice(record, receiverUserId, tenantId, remindUserName,templateName,orgName);
        }
    }

    // 批量解析健康证接收人：subjectId -> userId
    private Map<String, String> resolveHealthReceivers(List<CertificateInstanceEntity> records) {
        if (CollUtil.isEmpty(records)) {
            return Collections.emptyMap();
        }
        Set<String> subjectIds = records.stream()
                .map(r -> StrUtil.trim(r.getSubjectId()))
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toSet());
        if (CollUtil.isEmpty(subjectIds)) {
            return Collections.emptyMap();
        }
        // 健康证subjectId就是userId，直接映射
        Map<String, String> result = new HashMap<>(subjectIds.size());
        subjectIds.forEach(id -> result.put(id, id));
        return result;
    }

    // 批量解析非健康证接收人：subjectId(组织/门店) -> leaderId
    private Map<String, String> resolveOrgReceivers(List<CertificateInstanceEntity> records) {
        if (CollUtil.isEmpty(records)) {
            return Collections.emptyMap();
        }
        Set<String> subjectIds = records.stream()
                .map(r -> StrUtil.trim(r.getSubjectId()))
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toSet());
        if (CollUtil.isEmpty(subjectIds)) {
            return Collections.emptyMap();
        }
        Map<String, OrganizeGeneralDetailVO> organizeMap = organizationHelper.buildOrganizeGenerals(subjectIds);
        Map<String, String> result = new HashMap<>(subjectIds.size());
        for (String subjectId : subjectIds) {
            OrganizeGeneralDetailVO org = organizeMap.get(subjectId);
            if (org != null && StrUtil.isNotBlank(org.getLeaderId())) {
                result.put(subjectId, StrUtil.trim(org.getLeaderId()));
            }
        }
        return result;
    }


    /**
     * 左边是 组织接收人。key为subjectId，value为组织负责人id
     * 中间是 组织名称，key为组织id，value为组织名称
     * 右边是 模板名称，key为模板id，value为模板名称
     * @param records
     * @return
     */
    private MutableTriple<Map<String,String>,Map<String,String>,Map<String,String>>
    buildOrgReceiversAndOrgNamesAndTemplateNames(List<CertificateInstanceEntity> records) {
        if (CollUtil.isEmpty(records)) {
            return MutableTriple.of(Collections.emptyMap(),Collections.emptyMap(),Collections.emptyMap());
        }

        Set<String> templateIds = new HashSet<>();
        Set<String> orgIds = new HashSet<>();
        for (CertificateInstanceEntity record:records){
            String templateId = record.getTemplateId();
            if(StringUtil.isNotBlank(templateId)){
                templateIds.add(templateId);
            }
            orgIds.add(record.getSubjectId());
        }

        Map<String,String> orgReceivers = new HashMap<>();
        Map<String,String> orgNames = new HashMap<>();

        Map<String, OrganizeGeneralDetailVO> organizeMap = organizationHelper.buildOrganizeGenerals(orgIds);
        Map<String,String> templateNames = storeCertificatePhotoHelper.buildStoreCertificateIdAndNames(templateIds,null);
        for (String orgId : orgIds) {
            OrganizeGeneralDetailVO org = organizeMap.get(orgId);
            if(Objects.isNull(org)){
                continue;
            }
            if (StrUtil.isNotBlank(org.getLeaderId())) {
                orgReceivers.put(orgId, StrUtil.trim(org.getLeaderId()));
            }
            orgNames.put(orgId,org.getName());
        }
        return MutableTriple.of(orgReceivers,orgNames,templateNames);
    }

    /**
     * 单个提醒。
     * 根据证照实例ID查询后，按证照类型解析接收人并发送提醒。
     */
    @Override
    public void singleRemind(CertificateAppSingleRemindReq req) {
        ServiceException.notNull(req, "请求参数不能为空");
        List<String> certificateInstanceIds = req.getCertificateInstanceIds();
        ServiceException.isTrue(CollUtil.isNotEmpty(certificateInstanceIds), "证照实例ID不能为空");

        // 查询证照实例
        List<CertificateInstanceEntity> certificateInstanceEntities = certificateInstanceMapper.selectBatchIds(certificateInstanceIds);
        if(CollUtil.isEmpty(certificateInstanceEntities)){
            log.warn("证照实例不存在，certificateInstanceId={}", certificateInstanceIds);
            return;
        }

        Set<String> templateIds = new HashSet<>();
        Set<String> orgIds = new HashSet<>();
        for (CertificateInstanceEntity record:certificateInstanceEntities) {
            if (record.getStatus() == null || Integer.valueOf(STATUS_NORMAL).equals(record.getStatus())) {
                log.warn("证照状态无需提醒，certificateInstanceId={}, status={}", record.getId(), record.getStatus());
                continue;
            }
            String templateId = record.getTemplateId();
            Integer subjectType = record.getSubjectType();
            String subjectId = record.getSubjectId();
            if(StringUtil.isNotBlank(templateId)){
                templateIds.add(templateId);
            }
            if(Objects.nonNull(subjectType) && subjectType != SUBJECT_TYPE_EMPLOYEE){
                orgIds.add(subjectId);
            }
        }

        Map<String,String> templateIdAndNames = storeCertificatePhotoHelper.buildStoreCertificateIdAndNames(templateIds,null);
        Map<String, OrganizeBaseInfoVO> organizeBaseInfoById = organizationHelper.buildBaseOrganizeVO(orgIds,UserProvider.getUser().getTenantId());

        for (CertificateInstanceEntity record:certificateInstanceEntities){
            if (record.getStatus() == null || Integer.valueOf(STATUS_NORMAL).equals(record.getStatus())) {
                log.warn("证照状态无需提醒，certificateInstanceId={}, status={}", record.getId(), record.getStatus());
                continue;
            }

            // 解析接收人
            String receiverUserId = resolveSingleReceiverUserId(record,organizeBaseInfoById);
            if (StrUtil.isBlank(receiverUserId)) {
                log.warn("未找到提醒接收人，certificateInstanceId={}, subjectType={}, subjectId={}",
                        record.getId(), record.getSubjectType(), record.getSubjectId());
                continue;
            }

            String tenantId = UserProvider.getUser().getTenantId();
            String remindUserName = StrUtil.blankToDefault(StrUtil.trim(UserProvider.getUser().getUserName()), "系统");

            String templateName = templateIdAndNames.get(record.getTemplateId());
            String orgName = null;
            OrganizeBaseInfoVO organizeBaseInfoVO = organizeBaseInfoById.get(record.getSubjectId());
            if(Objects.nonNull(organizeBaseInfoVO)){
                orgName = organizeBaseInfoVO.getName();
            }

            sendNotice(record, receiverUserId, tenantId, remindUserName,templateName,orgName);
        }
    }

    /**
     * 解析单条提醒的接收人用户ID。
     * 健康证：通过V2UserApi#getUsersBound查询员工本人信息。
     * 非健康证：通过OrganizationHelper#buildOrganizeGenerals查询组织负责人。
     */
    private String resolveSingleReceiverUserId(CertificateInstanceEntity record,Map<String, OrganizeBaseInfoVO> organizeBaseInfoById) {
        String subjectId = StrUtil.trim(record.getSubjectId());
        if (StrUtil.isBlank(subjectId)) {
            return null;
        }
        if (isHealthCertificate(record.getCertificateType())) {
            return subjectId;
        }
        OrganizeBaseInfoVO organize = organizeBaseInfoById.get(subjectId);
        if (organize == null) {
            log.error("组织信息不存在，subjectId={}", subjectId);
            return null;
        }
        return StrUtil.trim(organize.getLeaderId());
    }

    /**
     * 发送单条提醒消息。
     */
    private void sendNotice(CertificateInstanceEntity record,
                            String receiverUserId,
                            String tenantId,
                            String remindUserName,
                            String templateName,
                            String orgName) {
        if (record == null) {
            return;
        }
        if (StrUtil.isBlank(receiverUserId)) {
            return;
        }
        NoticeMessage noticeMessage = buildNoticeMessage(record, remindUserName,templateName,orgName);

        if(isHealthCertificate(record.getCertificateType())){
            noticeHelper.sendMessage(
                    Collections.singletonList(receiverUserId),
                    tenantId,
                    noticeMessage.getTitle(),
                    noticeMessage.getContent(),
                    NoticeHelper.BUTTON_NAME_HANDLER,
                    buildJumpHealthCertificateUrl(record),
                    NoticeHelper.MP_ID_CERTIFICATE
            );
            return;
        }
        noticeHelper.sendMessage(
                Collections.singletonList(receiverUserId),
                tenantId,
                noticeMessage.getTitle(),
                noticeMessage.getContent(),
                null,
                null,
                null
        );
    }

    private String buildJumpHealthCertificateUrl(CertificateInstanceEntity record) {
        if(Objects.isNull(record)){
            return null;
        }
        String subjectId = record.getSubjectId();
        if(StringUtil.isBlank(subjectId)){
            return null;
        }
        return String.format(URL_CERTIFICATE,record.getId());
    }

    /**
     * 构建提醒文案。
     * 文案依据原型：标题“存在风险，请及时处理”，正文按缺失/临期/过期区分。
     */
    private NoticeMessage buildNoticeMessage(CertificateInstanceEntity record,
                                             String remindUserName,
                                             String templateName,
                                             String orgName) {
        String certificateType = StrUtil.trim(record.getCertificateType());
        Integer status = record.getStatus();
        String certificateName = resolveCertificateTypeName(certificateType,templateName);
        int remainDays = calculateRemainDays(record.getExpireDate());
        String subjectName = StrUtil.blankToDefault(orgName,StrUtil.blankToDefault(SubjectNameUtils.getSubjectName(record.getSubjectType()), "该主体"));

        if (isHealthCertificate(certificateType)) {
            String title = "您的健康证存在风险，请及时处理！";
            if (Integer.valueOf(STATUS_NEAR_EXPIRE).equals(status)) {
                return new NoticeMessage(title, buildHealthCertificateNearExpireContent(remainDays,remindUserName));
            }
            if (Integer.valueOf(STATUS_EXPIRED).equals(status)) {
                return new NoticeMessage(title, String.format("您的健康证已过期，%s提醒您及时更新健康证。", remindUserName));
            }
            return new NoticeMessage(title, String.format("您的健康证缺失，%s提醒您及时更新健康证。", remindUserName));
        }

        String title = subjectName + certificateName + "存在风险，请及时处理！";
        if (Integer.valueOf(STATUS_NEAR_EXPIRE).equals(status)) {
            return new NoticeMessage(title, buildCertificateNearExpireContent(subjectName,certificateName,remainDays));
        }
        if (Integer.valueOf(STATUS_EXPIRED).equals(status)) {
            return new NoticeMessage(title, String.format("%s%s已过期，请及时更新%s。", subjectName, certificateName, certificateName));
        }
        return new NoticeMessage(title, String.format("%s%s缺失，请及时上传%s。", subjectName, certificateName, certificateName));
    }

    private String buildCertificateNearExpireContent(String subjectName, String certificateName, int remainDays) {
        if(remainDays <= 0){
            return String.format("%s%s今天过期，请及时更新%s。", subjectName, certificateName, certificateName);
        }
        return String.format("%s%s离到期时间还有%s天，请及时更新%s。", subjectName, certificateName, remainDays, certificateName);
    }

    private String buildHealthCertificateNearExpireContent(int remainDays,String remindUserName) {
        if(remainDays <= 0){
            return String.format("您的健康证今天过期，%s提醒您请及时更新健康证。", remindUserName);
        }
        return String.format("您的健康证离到期时间还有%s天，%s提醒您请及时更新健康证。", remainDays,remindUserName);
    }

    /**
     * 单条提醒权限校验。
     */
    private void validateSinglePermission(CertificateAppReminderRecord record, String userId, String moduleId) {
        Integer subjectType = record.getSubjectType();
        if (Integer.valueOf(SUBJECT_TYPE_EMPLOYEE).equals(subjectType)) {
            PermissionUserScope userScope = resolvePermissionUserScope(userId, moduleId);
            if (Boolean.TRUE.equals(userScope.getAllDataPermission())) {
                return;
            }
            ServiceException.isTrue(CollUtil.isNotEmpty(userScope.getUserIds()), "暂无数据权限");
            ServiceException.isTrue(userScope.getUserIds().contains(StrUtil.trim(record.getReceiverUserId())), "暂无当前证照数据权限");
            return;
        }

        if (Integer.valueOf(SUBJECT_TYPE_ORGANIZATION).equals(subjectType) || Integer.valueOf(SUBJECT_TYPE_STORE).equals(subjectType)) {
            PermissionOrgScope orgScope = resolvePermissionOrgScope(userId, moduleId,UserProvider.getUser().getTenantId());
            if (Boolean.TRUE.equals(orgScope.getAllDataPermission())) {
                return;
            }
            String orgPermissionId = StrUtil.trim(record.getOrgPermissionId());
            ServiceException.isTrue(StrUtil.isNotBlank(orgPermissionId), "组织数据不存在，无法提醒");
            ServiceException.isTrue(CollUtil.isNotEmpty(orgScope.getOrgIds()), "暂无数据权限");
            ServiceException.isTrue(orgScope.getOrgIds().contains(orgPermissionId), "暂无当前证照数据权限");
            return;
        }
        throw new ServiceException("主体类型不支持提醒");
    }

    /**
     * 解析员工维度权限范围。
     * allDataPermission=true 代表全量权限，false 时使用 userIds 过滤。
     */
    private PermissionUserScope resolvePermissionUserScope(String userId, String moduleId) {
        List<String> permissionUserIds = permissionsUtils.obtainPersonnelUserIdDataPermissions(userId, moduleId);
        if (permissionUserIds == null) {
            return new PermissionUserScope(true, Collections.emptyList());
        }
        return new PermissionUserScope(false, normalizeIdList(permissionUserIds));
    }

    /**
     * 解析组织维度权限范围。
     * allDataPermission=true 代表全量权限，false 时使用 orgIds 过滤。
     */
    private PermissionOrgScope resolvePermissionOrgScope(String userId, String moduleId,String tenantId) {
        if (Boolean.TRUE.equals(UserProvider.getUser().getIsAdministrator())) {
            return new PermissionOrgScope(true, Collections.emptyList());
        }

        PermissionsApplicableObject applicableObject = permissionsUtils.obtainTheScopeOfUserPermissionsEnums(userId, moduleId,tenantId);
        PermissionsApplicableEnums applicableEnums = applicableObject == null ? null : applicableObject.getPermissionsApplicableEnums();
        if (PermissionsApplicableEnums.ALL.equals(applicableEnums)) {
            return new PermissionOrgScope(true, Collections.emptyList());
        }

        List<String> orgIds = normalizeIdList(applicableObject == null ? Collections.emptyList() : applicableObject.getOrgIds());
        if (CollUtil.isEmpty(orgIds)) {
            try {
                List<String> fallbackOrgIds = permissionsUtils.obtainPersonnelOrganizationIdDataPermissions(userId);
                if (fallbackOrgIds == null) {
                    return new PermissionOrgScope(true, Collections.emptyList());
                }
                orgIds = normalizeIdList(fallbackOrgIds);
            } catch (Exception e) {
                return new PermissionOrgScope(false, Collections.emptyList());
            }
        }
        return new PermissionOrgScope(false, orgIds);
    }

    /**
     * 规整ID集合：去空、去重、去首尾空格。
     */
    private List<String> normalizeIdList(Collection<String> idList) {
        if (CollUtil.isEmpty(idList)) {
            return Collections.emptyList();
        }
        return idList.stream()
                .filter(StrUtil::isNotBlank)
                .map(StrUtil::trim)
                .distinct()
                .collect(Collectors.toList());
    }

    /**
     * 是否健康证类型。
     */
    private boolean isHealthCertificate(String certificateType) {
        return StrUtil.equalsIgnoreCase(certificateType, CertificateTypeEnum.HEALTH_CERTIFICATE.getType());
    }

    /**
     * 证照类型转中文名称。
     */
    private String resolveCertificateTypeName(String certificateType,String templateName) {
        if (StrUtil.equalsIgnoreCase(certificateType, CertificateTypeEnum.HEALTH_CERTIFICATE.getType())) {
            return "健康证";
        }
        if (StrUtil.equalsIgnoreCase(certificateType, CertificateTypeEnum.BUSINESS_LICENSE.getType())) {
            return "营业执照";
        }
        if (StrUtil.equalsIgnoreCase(certificateType, CertificateTypeEnum.HYGIENE_LICENSE.getType())) {
            return "食品经营许可证";
        }
        if (StrUtil.equalsIgnoreCase(certificateType, CertificateTypeEnum.STORE_CUSTOM_CERTIFICATE.getType())) {
            return templateName;
        }
        return "证照";
    }

    /**
     * 计算距离到期的剩余天数。
     */
    private int calculateRemainDays(Date expireDate) {
        if (expireDate == null) {
            return 0;
        }
        Date today = DateUtil.beginOfDay(DateUtil.date());
        Date target = DateUtil.beginOfDay(expireDate);
        long days = DateUtil.betweenDay(today, target, false);
        return (int) Math.max(days, 0L);
    }

    /**
     * 员工权限范围。
     */
    private static class PermissionUserScope {
        private final Boolean allDataPermission;
        private final List<String> userIds;

        private PermissionUserScope(Boolean allDataPermission, List<String> userIds) {
            this.allDataPermission = allDataPermission;
            this.userIds = userIds;
        }

        public Boolean getAllDataPermission() {
            return allDataPermission;
        }

        public List<String> getUserIds() {
            return userIds;
        }
    }

    /**
     * 组织权限范围。
     */
    private static class PermissionOrgScope {
        private final Boolean allDataPermission;
        private final List<String> orgIds;

        private PermissionOrgScope(Boolean allDataPermission, List<String> orgIds) {
            this.allDataPermission = allDataPermission;
            this.orgIds = orgIds;
        }

        public Boolean getAllDataPermission() {
            return allDataPermission;
        }

        public List<String> getOrgIds() {
            return orgIds;
        }
    }

    /**
     * 提醒文案对象。
     */
    private static class NoticeMessage {
        private final String title;
        private final String content;

        private NoticeMessage(String title, String content) {
            this.title = title;
            this.content = content;
        }

        public String getTitle() {
            return title;
        }

        public String getContent() {
            return content;
        }
    }
}
