package jnpf.attendance.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.mapper.AttendanceBookConfigMapper;
import jnpf.attendance.mapper.AttendanceBookRecordMapper;
import jnpf.attendance.service.AttendanceBookConfigService;
import jnpf.attendance.service.AttendanceLeaveTypeService;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.attendance.service.RuleScopeService;
import jnpf.base.ActionResult;
import jnpf.base.service.SuperServiceImpl;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.AttendanceBookConfigEntity;
import jnpf.entity.attendance.AttendanceBookRecordEntity;
import jnpf.entity.attendance.AttendanceLeaveType;
import jnpf.entity.attendance.AttendanceRuleScope;
import jnpf.enums.attendance.AttendanceStatusEnum;
import jnpf.enums.attendance.ScopeBizType;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.AttendanceBookConfigAddUserDto;
import jnpf.model.attendance.dto.AttendanceBookConfigDto;
import jnpf.model.attendance.dto.AttendanceBookConfigQueryDto;
import jnpf.model.attendance.dto.GetValidUsersDto;
import jnpf.model.attendance.vo.*;
import jnpf.permission.V2OrganizeApi;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.util.*;
import jnpf.util.attendance.RuleScopeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 考勤本配置服务实现
 *
 * 设计说明：
 * 1. 考勤本配置独立管理，包含名称、使用范围、负责人等信息
 * 2. 负责人和可排假期都支持多选，用逗号拼接存储
 * 3. 优化：统一查询用户信息，避免多次调用API
 *
 * 已实现需求：
 * - 需求1：考勤本名称去空格+重复性校验
 * - 需求2：创建人列表接口
 * - 需求3：人员列表接口
 * - 需求9：列表负责人过滤
 *
 * @author Generated
 * @create 2026-04-15
 */
@Slf4j
@Service
public class AttendanceBookConfigServiceImpl extends SuperServiceImpl<AttendanceBookConfigMapper, AttendanceBookConfigEntity> implements AttendanceBookConfigService {

    // ==================== 常量定义 ====================
    // 注：所有业务常量已迁移至 AttendanceConstant 类

    @Autowired
    private RuleScopeUtil ruleScopeUtil;
    @Autowired
    private RuleScopeService ruleScopeService;
    @Autowired
    private AttendanceUserService attendanceUserService;
    @Autowired
    private UserAntifreeze userAntifreeze;
    @Resource
    private AttendanceLeaveTypeService attendanceLeaveTypeService;
    @Resource
    private V2OrganizeApi v2OrganizeApi;
    @Resource
    private AttendanceBookRecordMapper attendanceBookRecordMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveOrUpdateAttendanceBookConfig(AttendanceBookConfigDto configDto) throws HandleException {
        if (StringUtils.isBlank(configDto.getId())) {
            addAttendanceBookConfig(configDto);
        } else {
            updateAttendanceBookConfig(configDto.getId(), configDto);
        }
    }

    private void addAttendanceBookConfig(AttendanceBookConfigDto configDto) throws HandleException {
        // 需求1：考勤本名称去空格处理
        String bookName = configDto.getBookName();
        if (StringUtils.isNotBlank(bookName)) {
            configDto.setBookName(bookName.trim());
        }

        // 需求1：考勤本名称重复性校验
        validateBookNameDuplicate(null, configDto.getBookName());

        AttendanceBookConfigEntity config = getAttendanceBookConfig(configDto);
        List<AttendanceRuleScope> ruleScopeList = ruleScopeUtil.getRuleScopeList(
                config.getId(),
                configDto.getScopeType(),
                MutablePair.of(configDto.getOrganizeList(), configDto.getUserIdList()),
                ScopeBizType.ATTENDANCE_BOOK
        );
        this.save(config);
        if (!ruleScopeList.isEmpty()) {
            ruleScopeUtil.saveBatch(ruleScopeList);
        }
    }

    private void updateAttendanceBookConfig(String id, AttendanceBookConfigDto configDto) throws HandleException {
        // 需求1：考勤本名称去空格处理
        String bookName = configDto.getBookName();
        if (StringUtils.isNotBlank(bookName)) {
            configDto.setBookName(bookName.trim());
        }

        // 需求1：考勤本名称重复性校验（排除当前记录）
        validateBookNameDuplicate(id, configDto.getBookName());

        AttendanceBookConfigEntity config = this.getById(id);
        if (null == config) {
            throw new HandleException(AttendanceConstant.ERR_CONFIG_NOT_FOUND);
        }
        Integer oldScope = config.getScopeType();
        Integer newScope = configDto.getScopeType();

        validateScopeChangeWhenRecordsExist(id, oldScope, newScope, configDto);

        config.setBookName(configDto.getBookName());
        config.setScopeType(configDto.getScopeType());
        config.setManagerIds(configDto.getManagerIds());
        config.setHolidayScopeType(configDto.getHolidayScopeType());
        config.setHolidayIds(configDto.getHolidayIds());
        config.setEnabledMark(configDto.getEnabledMark() != null ? configDto.getEnabledMark() : ConstantUtil.NUM_TRUE);
        config.setLastModifyTime(DateUtil.getNowDate());
        config.setLastModifyUserId(UserProvider.getLoginUserId());
        this.updateById(config);

        ruleScopeUtil.updateRuleScopeList(
                id,
                oldScope,
                newScope,
                MutablePair.of(configDto.getOrganizeList(), configDto.getUserIdList()),
                ScopeBizType.ATTENDANCE_BOOK
        );
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteAttendanceBookConfig(String id) {
        this.update(new LambdaUpdateWrapper<AttendanceBookConfigEntity>()
                .set(AttendanceBookConfigEntity::getDeleteMark, ConstantUtil.NUM_TRUE)
                .set(AttendanceBookConfigEntity::getDeleteTime, DateUtil.getNowDate())
                .set(AttendanceBookConfigEntity::getDeleteUserId, UserProvider.getLoginUserId())
                .eq(AttendanceBookConfigEntity::getId, id));
        ruleScopeService.remove(new LambdaQueryWrapper<AttendanceRuleScope>()
                .eq(AttendanceRuleScope::getRuleId, id)
                .eq(AttendanceRuleScope::getBizType, ScopeBizType.ATTENDANCE_BOOK.getValue()));
    }

    @Override
    public void updateEnableStatus(String id) throws HandleException {
        AttendanceBookConfigEntity config = this.getById(id);
        if (null == config) {
            throw new HandleException(AttendanceConstant.ERR_CONFIG_NOT_EXIST);
        }

        this.update(new LambdaUpdateWrapper<AttendanceBookConfigEntity>()
                .set(AttendanceBookConfigEntity::getEnabledMark,
                        config.getEnabledMark().equals(ConstantUtil.NUM_TRUE) ? ConstantUtil.NUM_FALSE : ConstantUtil.NUM_TRUE)
                .set(AttendanceBookConfigEntity::getLastModifyTime, DateUtil.getNowDate())
                .set(AttendanceBookConfigEntity::getLastModifyUserId, UserProvider.getLoginUserId())
                .eq(AttendanceBookConfigEntity::getId, id));
    }

    @Override
    public AttendanceBookConfigVo getDetail(String id) {
        AttendanceBookConfigEntity config = this.getById(id);
        return setDetailInfo(config);
    }

    /**
     * 设置详细信息（优化版：统一查询用户信息）
     *
     * 优化点：
     * 1. 提前返回，减少嵌套
     * 2. 抽取查询逻辑，职责分离
     * 3. 使用 Optional 处理空值
     * 4. 常量提取，提高可读性
     * 5. 参考OvertimeRuleServiceImpl.setDetailInfo方法，添加使用范围查询
     */
    private AttendanceBookConfigVo setDetailInfo(AttendanceBookConfigEntity config) {
        if (config == null) {
            return null;
        }

        // 1. 基础信息转换
        AttendanceBookConfigVo vo = JsonUtil.getJsonToBean(config, AttendanceBookConfigVo.class);

        // 2. 查询使用范围（参考OvertimeRuleServiceImpl.setDetailInfo方法）
        MutablePair<List<String>, List<String>> scopeData = ruleScopeUtil.selectScopeList(
                vo.getId(),
                ScopeBizType.ATTENDANCE_BOOK
        );
        if (null != scopeData) {
            if (scopeData.getLeft().isEmpty() && scopeData.getRight().isEmpty()) {
                // 无适配范围，说明是"全部"
                vo.setScopeType(-1);
            } else {
                vo.getOrganizeList().addAll(scopeData.getLeft());
                vo.getUserIdList().addAll(scopeData.getRight());
            }
        }

        // 3. 查询并构建用户信息映射
        Map<String, PartUserInfoVo> userMap = buildUserMap(config);

        // 4. 设置展示字段
        vo.setScopeDisplayText(buildScopeDisplayText(config, userMap));
        vo.setManagerList(buildManagerList(config.getManagerIds(), userMap));
        vo.setCreatorUserName(getUserName(config.getCreatorUserId(), userMap));

        // 5. 设置假期相关信息
        setHolidayInfo(vo, config);

        return vo;
    }

    /**
     * 构建用户信息映射（统一查询）
     */
    private Map<String, PartUserInfoVo> buildUserMap(AttendanceBookConfigEntity config) {
        Set<String> allUserIds = collectAllUserIds(config);

        if (allUserIds.isEmpty()) {
            return Collections.emptyMap();
        }

        return queryUserMap(allUserIds);
    }

    /**
     * 批量查询并转换为VO列表（优化版：避免N+1问题）
     */
    private List<AttendanceBookConfigVo> convertToVoListWithBatchQuery(List<AttendanceBookConfigEntity> entityList) {
        if (CollUtil.isEmpty(entityList)) {
            return Collections.emptyList();
        }

        // 1. 收集所有需要查询的用户ID
        Set<String> allUserIds = new HashSet<>();
        // 收集所有需要查询的规则ID（用于查询使用范围）
        List<String> ruleIds = new ArrayList<>();

        for (AttendanceBookConfigEntity config : entityList) {
            ruleIds.add(config.getId());
            // 收集负责人ID
            allUserIds.addAll(parseIdsToList(config.getManagerIds()));
            // 收集创建人ID
            if (StringUtils.isNotBlank(config.getCreatorUserId())) {
                allUserIds.add(config.getCreatorUserId());
            }
        }

        // 1.5. 批量查询使用范围，收集使用范围中的用户ID
        Map<String, MutablePair<List<String>, List<String>>> scopeMap = ruleScopeUtil.selectScopeListBatch(ruleIds, ScopeBizType.ATTENDANCE_BOOK);
        for (MutablePair<List<String>, List<String>> scope : scopeMap.values()) {
            if (scope != null && scope.getRight() != null) {
                allUserIds.addAll(scope.getRight());
            }
        }

        // 2. 批量查询用户信息
        Map<String, PartUserInfoVo> userMap = queryUserMap(allUserIds);

        // 3. 批量查询假期信息（只需要查询一次）
        Map<String, AttendanceLeaveType> leaveMap = buildLeaveMap(null);

        // 4. 转换为VO列表
        List<AttendanceBookConfigVo> voList = new ArrayList<>();
        for (AttendanceBookConfigEntity config : entityList) {
            AttendanceBookConfigVo vo = convertToVoWithCachedData(config, userMap, leaveMap, scopeMap);
            voList.add(vo);
        }

        return voList;
    }

    /**
     * 使用缓存的数据转换为VO（避免重复查询）
     */
    private AttendanceBookConfigVo convertToVoWithCachedData(AttendanceBookConfigEntity config,
                                                             Map<String, PartUserInfoVo> userMap,
                                                             Map<String, AttendanceLeaveType> leaveMap,
                                                             Map<String, MutablePair<List<String>, List<String>>> scopeMap) {
        // 1. 基础信息转换
        AttendanceBookConfigVo vo = JsonUtil.getJsonToBean(config, AttendanceBookConfigVo.class);

        // 2. 设置使用范围展示文本（使用缓存的使用范围数据）
        MutablePair<List<String>, List<String>> scopeData = scopeMap.get(config.getId());
        vo.setScopeDisplayText(buildScopeDisplayTextWithCache(config, userMap, scopeData));

        // 3. 设置负责人列表
        vo.setManagerList(buildManagerList(config.getManagerIds(), userMap));

        // 4. 设置创建人姓名（使用缓存的用户信息）
        vo.setCreatorUserName(getUserName(config.getCreatorUserId(), userMap));

        // 5. 设置假期相关信息（使用缓存的假期信息）
        vo.setHolidayDisplayText(buildHolidayDisplayTextWithCache(config, leaveMap));
        vo.setHolidayTypes(buildHolidayTypesWithCache(config.getHolidayIds(), leaveMap));

        return vo;
    }

    /**
     * 使用缓存的假期信息构建假期展示文本
     */
    private String buildHolidayDisplayTextWithCache(AttendanceBookConfigEntity config,
                                                    Map<String, AttendanceLeaveType> leaveMap) {
        if (config.getHolidayScopeType() == null) {
            return "";
        }

        if (Integer.valueOf(1).equals(config.getHolidayScopeType())) {
            return "全部假期";
        }

        if (StringUtils.isBlank(config.getHolidayIds())) {
            return "";
        }

        List<String> holidayIdList = parseIdsToList(config.getHolidayIds());

        return holidayIdList.stream()
                .map(leaveMap::get)
                .filter(Objects::nonNull)
                .map(AttendanceLeaveType::getName)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.joining(","));
    }

    /**
     * 使用缓存的假期信息构建假期类型列表
     */
    private List<HolidayTypeVo> buildHolidayTypesWithCache(String holidayIds,
                                                           Map<String, AttendanceLeaveType> leaveMap) {
        List<String> holidayIdList = parseIdsToList(holidayIds);
        if (holidayIdList.isEmpty()) {
            return Collections.emptyList();
        }

        return holidayIdList.stream()
                .map(leaveMap::get)
                .filter(Objects::nonNull)
                .map(leave -> HolidayTypeVo.builder()
                        .id(leave.getId())
                        .name(leave.getName())
                        .build())
                .collect(Collectors.toList());
    }

    /**
     * 收集所有需要查询的用户ID
     */
    private Set<String> collectAllUserIds(AttendanceBookConfigEntity config) {

        // 收集负责人ID
        Set<String> userIds = new HashSet<>(parseIdsToList(config.getManagerIds()));

        // 收集创建人ID
        Optional.ofNullable(config.getCreatorUserId())
                .filter(StringUtils::isNotBlank)
                .ifPresent(userIds::add);

        // 收集使用范围中的用户ID
        if (isOrgUserScope(config)) {
            List<String> scopeUserIds = getScopeUserIds(config.getId());
            userIds.addAll(scopeUserIds);
        }

        return userIds;
    }

    /**
     * 查询用户信息并构建Map
     */
    private Map<String, PartUserInfoVo> queryUserMap(Set<String> userIds) {
        try {
            List<PartUserInfoVo> result = userAntifreeze.getStaffRosterListInfoByIds(
                    new ArrayList<>(userIds)
            );

            if (CollUtil.isEmpty(result)) {
                return Collections.emptyMap();
            }

            return result.stream()
                    .filter(user -> user != null && user.getUserId() != null)
                    .collect(Collectors.toMap(
                            PartUserInfoVo::getUserId,
                            user -> user,
                            (existing, replacement) -> existing
                    ));
        } catch (Exception e) {
            log.error("统一查询用户信息失败, userIds: {}", userIds, e);
            return Collections.emptyMap();
        }
    }

    /**
     * 设置假期相关信息（仅查询一次有效假期类型，已删除的不展示）
     */
    private void setHolidayInfo(AttendanceBookConfigVo vo, AttendanceBookConfigEntity config) {
        if (config.getHolidayScopeType() == null) {
            vo.setHolidayDisplayText("");
            vo.setHolidayTypes(Collections.emptyList());
            return;
        }
        if (Integer.valueOf(1).equals(config.getHolidayScopeType())) {
            vo.setHolidayDisplayText("全部假期");
            vo.setHolidayTypes(Collections.emptyList());
            return;
        }
        if (StringUtils.isBlank(config.getHolidayIds())) {
            vo.setHolidayDisplayText("");
            vo.setHolidayTypes(Collections.emptyList());
            return;
        }
        Map<String, AttendanceLeaveType> leaveMap = buildLeaveMap(parseIdsToList(config.getHolidayIds()));
        vo.setHolidayDisplayText(buildHolidayDisplayTextWithCache(config, leaveMap));
        vo.setHolidayTypes(buildHolidayTypesWithCache(config.getHolidayIds(), leaveMap));
        vo.setHolidayIds(String.join(",", leaveMap.keySet()));
    }

    /**
     * 构建假期映射（仅包含未删除的假期类型）
     *
     * @param holidayIdList 指定 ID 列表；为空或 null 时查询全部有效假期
     */
    private Map<String, AttendanceLeaveType> buildLeaveMap(List<String> holidayIdList) {
        List<AttendanceLeaveType> leaveList = attendanceLeaveTypeService.getAttendanceLeaveTypes(
                CollUtil.isEmpty(holidayIdList) ? null : holidayIdList);
        if (leaveList == null || leaveList.isEmpty()) {
            return Collections.emptyMap();
        }

        return leaveList.stream()
                .filter(leave -> leave != null && leave.getId() != null)
                .collect(Collectors.toMap(
                        AttendanceLeaveType::getId,
                        leave -> leave,
                        (existing, replacement) -> existing
                ));
    }

    /**
     * 构建使用范围展示文本
     */
    private String buildScopeDisplayText(AttendanceBookConfigEntity config, Map<String, PartUserInfoVo> userMap) {
        if (ConstantUtil.SCOPE_ALL.equals(config.getScopeType())) {
            return "全部";
        }

        List<AttendanceRuleScope> scopes = queryRuleScopes(config.getId());
        if (scopes.isEmpty()) {
            return "";
        }

        return buildScopeDisplayTextFromScopes(scopes, userMap);
    }

    /**
     * 使用缓存的使用范围数据构建展示文本
     */
    private String buildScopeDisplayTextWithCache(AttendanceBookConfigEntity config,
                                                  Map<String, PartUserInfoVo> userMap,
                                                  MutablePair<List<String>, List<String>> scopeData) {
        if (ConstantUtil.SCOPE_ALL.equals(config.getScopeType())) {
            return "全部";
        }

        if (scopeData == null) {
            return "";
        }

        List<String> orgIds = scopeData.getLeft();
        List<String> userIds = scopeData.getRight();

        if ((orgIds == null || orgIds.isEmpty()) && (userIds == null || userIds.isEmpty())) {
            return "";
        }

        StringBuilder sb = new StringBuilder();

        // 处理组织：直接通过组织API查询组织名称
        if (orgIds != null && !orgIds.isEmpty()) {
            try {
                // 批量查询组织信息
                ActionResult<List<OrganizeGeneralDetailVO>> result = v2OrganizeApi.organizesByOrganizeIds(orgIds);

                if (result != null && result.getData() != null && CollUtil.isNotEmpty(result.getData())) {
                    List<OrganizeGeneralDetailVO> orgList = result.getData();
                    String orgNames = orgList.stream()
                            .filter(org -> org != null && StringUtils.isNotBlank(org.getName()))
                            .map(OrganizeGeneralDetailVO::getName)
                            .collect(Collectors.joining(","));

                    if (StringUtils.isNotBlank(orgNames)) {
                        sb.append("【使用的组织】:").append(orgNames);
                    } else {
                        sb.append("【使用的组织】:").append(String.join(",", orgIds));
                    }
                } else {
                    // 如果查询不到组织信息，显示组织ID
                    sb.append("【使用的组织】:").append(String.join(",", orgIds));
                }
            } catch (Exception e) {
                log.error("查询组织名称失败，orgIds: {}", orgIds, e);
                sb.append("【使用的组织】:").append(String.join(",", orgIds));
            }
        }

        // 处理用户
        if (userIds != null && !userIds.isEmpty()) {
            if (sb.length() > 0) {
                sb.append("; ");
            }

            String userNames = userIds.stream()
                    .map(userId -> Optional.ofNullable(userMap.get(userId))
                            .map(PartUserInfoVo::getRealName)
                            .orElse(userId))
                    .collect(Collectors.joining(","));

            sb.append("【使用的人员】:").append(userNames);
        }

        return sb.toString();
    }

    /**
     * 查询规则使用范围
     */
    private List<AttendanceRuleScope> queryRuleScopes(String ruleId) {
        return ruleScopeService.list(
                new LambdaQueryWrapper<AttendanceRuleScope>()
                        .eq(AttendanceRuleScope::getRuleId, ruleId)
                        .eq(AttendanceRuleScope::getBizType, ScopeBizType.ATTENDANCE_BOOK.getValue())
        );
    }

    /**
     * 从使用范围构建展示文本
     */
    private String buildScopeDisplayTextFromScopes(List<AttendanceRuleScope> scopes, Map<String, PartUserInfoVo> userMap) {
        List<String> orgIds = scopes.stream()
                .filter(s -> ConstantUtil.RULE_SCOPE_ORG.equals(s.getScopeType()))
                .map(AttendanceRuleScope::getScopeValue)
                .collect(Collectors.toList());

        List<String> userIds = scopes.stream()
                .filter(s -> ConstantUtil.RULE_SCOPE_USER.equals(s.getScopeType()))
                .map(AttendanceRuleScope::getScopeValue)
                .collect(Collectors.toList());

        if (orgIds.isEmpty() && userIds.isEmpty()) {
            return "";
        }

        StringBuilder sb = new StringBuilder();

        if (!orgIds.isEmpty()) {
            sb.append("【使用的组织】:").append(String.join(",", orgIds));
        }

        if (!userIds.isEmpty()) {
            appendUserNames(sb, userIds, userMap);
        }

        return sb.toString();
    }

    /**
     * 追加用户名称到 StringBuilder
     */
    private void appendUserNames(StringBuilder sb, List<String> userIds, Map<String, PartUserInfoVo> userMap) {
        if (sb.length() > 0) {
            sb.append("; ");
        }

        String userNames = userIds.stream()
                .map(userId -> Optional.ofNullable(userMap.get(userId))
                        .map(PartUserInfoVo::getRealName)
                        .orElse(userId))
                .collect(Collectors.joining(","));

        sb.append("【使用的人员】:").append(userNames);
    }

    /**
     * 构建负责人集合
     */
    private List<AttendanceGroupChargeVo> buildManagerList(String managerIds, Map<String, PartUserInfoVo> userMap) {
        List<String> managerIdList = parseIdsToList(managerIds);
        if (managerIdList.isEmpty()) {
            return Collections.emptyList();
        }

        return managerIdList.stream()
                .map(managerId -> buildChargeVo(managerId, userMap))
                .collect(Collectors.toList());
    }

    /**
     * 构建负责人 VO
     */
    private AttendanceGroupChargeVo buildChargeVo(String managerId, Map<String, PartUserInfoVo> userMap) {
        String managerName = getUserName(managerId, userMap);
        return AttendanceGroupChargeVo.builder()
                .managerId(managerId)
                .managerName(managerName)
                .build();
    }

    /**
     * 获取用户姓名
     */
    private String getUserName(String userId, Map<String, PartUserInfoVo> userMap) {
        String userName = Optional.ofNullable(userId)
                .filter(StringUtils::isNotBlank)
                .map(userMap::get)
                .map(PartUserInfoVo::getRealName)
                .orElse("");

        if (StringUtils.isNotBlank(userId) && StringUtils.isBlank(userName)) {
            log.warn("创建人ID: {} 在userMap中未找到对应的用户信息，userMap大小: {}", userId, userMap.size());
        }

        return userName;
    }

    /**
     * 解析ID列表（逗号分隔）
     */
    private List<String> parseIdsToList(String ids) {
        if (StringUtils.isBlank(ids)) {
            return Collections.emptyList();
        }

        return Arrays.stream(ids.split(","))
                .map(String::trim)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toList());
    }

    /**
     * 判断是否为组织/用户范围
     */
    private boolean isOrgUserScope(AttendanceBookConfigEntity config) {
        return ConstantUtil.SCOPE_ORG_USER.equals(config.getScopeType());
    }

    /**
     * 获取使用范围中的用户ID列表
     */
    private List<String> getScopeUserIds(String ruleId) {
        MutablePair<List<String>, List<String>> listListMutablePair = ruleScopeUtil.selectScopeList(ruleId, ScopeBizType.ATTENDANCE_BOOK);
        return ruleScopeService.list(
                        new LambdaQueryWrapper<AttendanceRuleScope>()
                                .eq(AttendanceRuleScope::getRuleId, ruleId)
                                .eq(AttendanceRuleScope::getBizType, ScopeBizType.ATTENDANCE_BOOK.getValue())
                                .eq(AttendanceRuleScope::getScopeType, ConstantUtil.RULE_SCOPE_USER)
                ).stream()
                .map(AttendanceRuleScope::getScopeValue)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toList());
    }

    private AttendanceBookConfigEntity getAttendanceBookConfig(AttendanceBookConfigDto configDto) {
        AttendanceBookConfigEntity config = new AttendanceBookConfigEntity();
        config.setId(FtbUtil.getId());
        config.setBookName(configDto.getBookName());
        config.setScopeType(configDto.getScopeType());
        config.setManagerIds(configDto.getManagerIds());
        config.setHolidayScopeType(configDto.getHolidayScopeType());
        config.setHolidayIds(configDto.getHolidayIds());
        config.setEnabledMark(configDto.getEnabledMark() != null ? configDto.getEnabledMark() : ConstantUtil.NUM_TRUE);
        config.setCreatorUserId(UserProvider.getLoginUserId());
        config.setCreatorTime(DateUtil.getNowDate());
        config.setLastModifyUserId(UserProvider.getLoginUserId());
        config.setLastModifyTime(DateUtil.getNowDate());
        config.setDeleteMark(ConstantUtil.NUM_FALSE);
        config.setTenantId(UserProvider.getUser().getTenantId());
        return config;
    }

    @Override
    public PageInfo<AttendanceBookConfigVo> getPageList(AttendanceBookConfigQueryDto queryDto) {
        log.info("分页查询考勤本配置列表，入参=> bookName: {}, enabledMark: {}, creatorUserIdList: {}, creatorStartTime: {}, creatorEndTime: {}, isManagerFilter: {}",
                queryDto.getBookName(), queryDto.getEnabledMark(), queryDto.getCreatorUserIdList(),
                queryDto.getCreatorStartTime(), queryDto.getCreatorEndTime(), queryDto.getIsManagerFilter());
        if (queryDto.getPageSize() > 0) {
            PageHelper.startPage(queryDto.getCurrentPage(), queryDto.getPageSize());
        }
        LambdaQueryWrapper<AttendanceBookConfigEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AttendanceBookConfigEntity::getDeleteMark, ConstantUtil.NUM_FALSE)
                .eq(AttendanceBookConfigEntity::getTenantId, UserProvider.getUser().getTenantId())
                .like(StringUtils.isNotBlank(queryDto.getBookName()),
                        AttendanceBookConfigEntity::getBookName, queryDto.getBookName())
                .eq(queryDto.getEnabledMark() != null,
                        AttendanceBookConfigEntity::getEnabledMark, queryDto.getEnabledMark());

        // 创建人集合过滤
        if (CollUtil.isNotEmpty(queryDto.getCreatorUserIdList())) {
            queryWrapper.in(AttendanceBookConfigEntity::getCreatorUserId, queryDto.getCreatorUserIdList());
        }

        // 修复时间搜索问题：结束日期应该包含当天的全部时间（直到23:59:59）
        if (queryDto.getCreatorStartTime() != null) {
            queryWrapper.ge(AttendanceBookConfigEntity::getCreatorTime, queryDto.getCreatorStartTime());
        }
        if (queryDto.getCreatorEndTime() != null) {
            // 使用Hutool工具类获取当天结束时间（23:59:59）
            Date endTime = cn.hutool.core.date.DateUtil.endOfDay(queryDto.getCreatorEndTime());
            queryWrapper.le(AttendanceBookConfigEntity::getCreatorTime, endTime);
        }

        // 需求9：按负责人过滤
        if (queryDto.getIsManagerFilter()) {
            queryWrapper.eq(AttendanceBookConfigEntity::getEnabledMark, 1);
            if (!UserProvider.getUser().getIsAdministrator()) {
                String currentUserId = UserProvider.getLoginUserId();
                queryWrapper.apply("F_ManagerIds LIKE {0}", "%" + currentUserId + "%");
            }
        }

        queryWrapper.orderByDesc(AttendanceBookConfigEntity::getCreatorTime);

        List<AttendanceBookConfigEntity> entityList = this.list(queryWrapper);
        log.info("查询到考勤本配置数量: {}", entityList.size());
        PageInfo<AttendanceBookConfigEntity> pageInfo = new PageInfo<>(entityList);

        // 优化：批量查询所有用户信息和假期信息，避免N+1问题
        List<AttendanceBookConfigVo> voList = convertToVoListWithBatchQuery(entityList);

        PageInfo<AttendanceBookConfigVo> result = new PageInfo<>();
        result.setList(voList);
        result.setTotal(pageInfo.getTotal());
        result.setPages(pageInfo.getPages());
        result.setPageNum(pageInfo.getPageNum());
        result.setPageSize(pageInfo.getPageSize());

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addScopeUsers(AttendanceBookConfigAddUserDto addUserDto) throws HandleException {
        String bookConfigId = addUserDto.getBookConfigId();
        List<String> userIdList = addUserDto.getUserIdList();

        AttendanceBookConfigEntity config = this.getById(bookConfigId);
        if (null == config) {
            throw new HandleException(AttendanceConstant.ERR_CONFIG_NOT_FOUND);
        }

        if (config.getScopeType().equals(ConstantUtil.SCOPE_ALL)) {
            throw new HandleException("当前考勤本使用范围为全部，无需添加人员");
        }

        List<AttendanceRuleScope> existingScopes = ruleScopeService.list(
                new LambdaQueryWrapper<AttendanceRuleScope>()
                        .eq(AttendanceRuleScope::getRuleId, bookConfigId)
                        .eq(AttendanceRuleScope::getBizType, ScopeBizType.ATTENDANCE_BOOK.getValue())
                        .eq(AttendanceRuleScope::getScopeType, ConstantUtil.RULE_SCOPE_USER)
        );

        Set<String> existingUserIds = existingScopes.stream()
                .map(AttendanceRuleScope::getScopeValue)
                .collect(Collectors.toSet());

        List<String> newUserIds = userIdList.stream()
                .filter(userId -> !existingUserIds.contains(userId))
                .collect(Collectors.toList());

        if (newUserIds.isEmpty()) {
            throw new HandleException("所有用户已在使用范围中，无需重复添加");
        }

        List<AttendanceRuleScope> newScopeList = newUserIds.stream()
                .map(userId -> ruleScopeUtil.getRuleScope(
                        bookConfigId,
                        userId,
                        ConstantUtil.RULE_SCOPE_USER,
                        ScopeBizType.ATTENDANCE_BOOK
                ))
                .collect(Collectors.toList());

        if (!newScopeList.isEmpty()) {
            ruleScopeUtil.saveBatch(newScopeList);
        }
    }

    @Override
    public boolean isCurrentUserManager(String bookConfigId) throws HandleException {
        AttendanceBookConfigEntity config = this.getById(bookConfigId);
        if (null == config) {
            throw new HandleException(AttendanceConstant.ERR_CONFIG_NOT_FOUND);
        }

        String currentUserId = UserProvider.getLoginUserId();

        if (StringUtils.isBlank(config.getManagerIds())) {
            return false;
        }

        List<String> managerIdList = Arrays.asList(config.getManagerIds().split(","));
        return managerIdList.stream()
                .map(String::trim)
                .anyMatch(managerId -> managerId.equals(currentUserId));
    }

    @Override
    public List<PartUserInfoVo> getValidUsers(GetValidUsersDto dto) {
        Integer scopeOrgUser = ConstantUtil.SCOPE_ORG_USER;
        if ((dto.getOrganizeList() == null || dto.getOrganizeList().isEmpty())
                && (dto.getUserIdList() == null || dto.getUserIdList().isEmpty())) {
            log.warn("组织列表和用户列表都为空");
            scopeOrgUser = ConstantUtil.SCOPE_ALL;
        }
        // 2. 解析月份，获取该月的起止日期
        Date startDate = new Date();
        Date endDate = new Date();
        if (StringUtil.isNotEmpty(dto.getMonth())) {
            YearMonth yearMonth = YearMonth.parse(dto.getMonth(), DateTimeFormatter.ofPattern("yyyy-MM"));
            startDate = Date.from(yearMonth.atDay(1).atStartOfDay().atZone(java.time.ZoneId.systemDefault()).toInstant());
            endDate = Date.from(yearMonth.atEndOfMonth().atTime(23, 59, 59).atZone(java.time.ZoneId.systemDefault()).toInstant());
        }
        List<String> userIds = attendanceUserService.getUserIds(
                dto.getOrganizeList(),
                dto.getUserIdList(),
                startDate,
                endDate,
                scopeOrgUser
        );

        if (CollUtil.isEmpty(userIds)) {
            return List.of();
        }

        try {
            List<PartUserInfoVo> result = userAntifreeze.getStaffRosterListInfoByIds(
                    userIds
            );

            if (result != null) {
                return result.stream()
                        .map(userBoundVO -> {
                            PartUserInfoVo partUserInfoVo = new PartUserInfoVo();
                            partUserInfoVo.setUserId(userBoundVO.getUserId());
                            partUserInfoVo.setRealName(userBoundVO.getRealName());
                            partUserInfoVo.setMobilePhone(userBoundVO.getMobilePhone());
                            partUserInfoVo.setOrganizeName(userBoundVO.getOrganizeName());
                            partUserInfoVo.setPositionName(userBoundVO.getPositionName());
                            return partUserInfoVo;
                        })
                        .collect(Collectors.toList());
            }
        } catch (Exception e) {
            log.error("查询用户详细信息失败", e);
        }

        return List.of();
    }

    @Override
    public AttendanceResultOptionGroupVo getAttendanceResultOptions(String bookConfigId) throws HandleException {
        log.info("获取考勤结果下拉列表（分组），bookConfigId: {}", bookConfigId);

        AttendanceBookConfigEntity config = this.getById(bookConfigId);
        if (config == null) {
            throw new HandleException(AttendanceConstant.ERR_CONFIG_NOT_FOUND);
        }

        // 1. 构建考勤结果选项（basic类型）
        List<AttendanceResultOptionVo> attendanceResults = new ArrayList<>();
        for (AttendanceStatusEnum status : AttendanceStatusEnum.getBasicStatuses()) {
            attendanceResults.add(AttendanceResultOptionVo.builder()
                    .value(String.valueOf(status.getCode()))
                    .label(status.getName())
                    .type(status.getType())
                    .build());
        }

        // 2. 构建外勤结果选项（out类型）
        List<AttendanceResultOptionVo> outResults = new ArrayList<>();
        for (AttendanceStatusEnum status : AttendanceStatusEnum.getOutStatuses()) {
            outResults.add(AttendanceResultOptionVo.builder()
                    .value(String.valueOf(status.getCode()))
                    .label(status.getName())
                    .type(status.getType())
                    .build());
        }

        // 3. 构建假期类型选项（leave类型，含已删除并返回删除标识）
        List<AttendanceResultOptionVo> leaveTypes = new ArrayList<>();
        if (Objects.equals(config.getHolidayScopeType(), 1)) {
            List<AttendanceLeaveType> allLeaveTypes = attendanceLeaveTypeService.getAttendanceLeaveTypesIncludeDeleted(null);
            leaveTypes.addAll(toLeaveResultOptions(allLeaveTypes));
        } else if (StringUtils.isNotBlank(config.getHolidayIds())) {
            List<String> holidayIdList = Arrays.stream(config.getHolidayIds().split(","))
                    .map(String::trim)
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.toList());
            List<AttendanceLeaveType> voList = attendanceLeaveTypeService.getAttendanceLeaveTypesIncludeDeleted(holidayIdList);
            leaveTypes.addAll(toLeaveResultOptions(voList));
        }

        AttendanceResultOptionGroupVo result = AttendanceResultOptionGroupVo.builder()
                .attendanceResults(attendanceResults)
                .outResults(outResults)
                .leaveTypes(leaveTypes)
                .build();

        log.info("获取考勤结果下拉列表成功，bookConfigId: {}, 考勤结果数: {}, 外勤结果数: {}, 假期类型数: {}",
                bookConfigId, attendanceResults.size(), outResults.size(), leaveTypes.size());
        return result;
    }

    private List<AttendanceResultOptionVo> toLeaveResultOptions(List<AttendanceLeaveType> leaveTypeList) {
        if (CollUtil.isEmpty(leaveTypeList)) {
            return Collections.emptyList();
        }
        List<AttendanceResultOptionVo> options = new ArrayList<>(leaveTypeList.size());
        for (AttendanceLeaveType leave : leaveTypeList) {
            options.add(AttendanceResultOptionVo.builder()
                    .value(leave.getId())
                    .label(leave.getName())
                    .type("leave")
                    .deleted(Objects.equals(leave.getDeleteMark(), ConstantUtil.NUM_TRUE))
                    .build());
        }
        return options;
    }

    @Override
    public List<BookConfigCreatorVo> getCreatorList() {
        log.info("获取考勤本配置创建人列表");

        // 1. 查询所有考勤本配置的创建人ID（去重）
        LambdaQueryWrapper<AttendanceBookConfigEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AttendanceBookConfigEntity::getDeleteMark, ConstantUtil.NUM_FALSE)
                .eq(AttendanceBookConfigEntity::getTenantId, UserProvider.getUser().getTenantId())
                .select(AttendanceBookConfigEntity::getCreatorUserId);

        List<AttendanceBookConfigEntity> configList = this.list(queryWrapper);
        if (CollUtil.isEmpty(configList)) {
            return Collections.emptyList();
        }

        // 2. 获取所有创建人ID（去重）
        List<String> creatorUserIds = configList.stream()
                .map(AttendanceBookConfigEntity::getCreatorUserId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());

        if (creatorUserIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 3. 查询创建人详细信息
        List<BookConfigCreatorVo> result = new ArrayList<>();
        try {
            List<PartUserInfoVo> userResult = userAntifreeze.getStaffRosterListInfoByIds(
                    creatorUserIds);

            if (userResult != null && !userResult.isEmpty()) {
                for (PartUserInfoVo user : userResult) {
                    result.add(BookConfigCreatorVo.builder()
                            .userId(user.getUserId())
                            .userName(user.getRealName())
                            .organizeName(user.getOrganizeName())
                            .build());
                }
            }
        } catch (Exception e) {
            log.error("查询创建人详细信息失败", e);
        }

        log.info("获取考勤本配置创建人列表成功，创建人数: {}", result.size());
        return result;
    }

    @Override
    public List<BookPersonnelVo> getBookPersonnelList(String bookConfigId, String month) {
        log.info("获取考勤本配置人员列表，bookConfigId: {}", bookConfigId);

        // 1. 查询考勤本配置
        AttendanceBookConfigEntity config = this.getById(bookConfigId);
        if (config == null) {
            log.warn("考勤本配置不存在，bookConfigId: {}", bookConfigId);
            return Collections.emptyList();
        }

        // 2. 获取使用范围
        MutablePair<List<String>, List<String>> scopeList = ruleScopeUtil.selectScopeList(
                bookConfigId, ScopeBizType.ATTENDANCE_BOOK);
        if (scopeList == null) {
            return Collections.emptyList();
        }
        // 2. 解析月份，获取该月的起止日期
        Date startDate = new Date();
        Date endDate = new Date();
        if (StringUtil.isNotEmpty(month)) {
            YearMonth yearMonth = YearMonth.parse(month, DateTimeFormatter.ofPattern("yyyy-MM"));
            startDate = Date.from(yearMonth.atDay(1).atStartOfDay().atZone(java.time.ZoneId.systemDefault()).toInstant());
            endDate = Date.from(yearMonth.atEndOfMonth().atTime(23, 59, 59).atZone(java.time.ZoneId.systemDefault()).toInstant());
        }
        // 3. 获取有效用户ID列表
        List<String> userIds = attendanceUserService.getUserIds(
                scopeList.getLeft(),
                scopeList.getRight(),
                startDate,
                endDate,
                config.getScopeType()
        );

        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }

        // 4. 查询用户详细信息
        List<PartUserInfoVo> userInfoList = userAntifreeze.getStaffRosterListInfoByIds(userIds);
        if (CollUtil.isEmpty(userInfoList)) {
            return Collections.emptyList();
        }

        // 5. 构建返回结果
        List<BookPersonnelVo> result = new ArrayList<>();
        for (PartUserInfoVo userInfo : userInfoList) {
            BookPersonnelVo personnelVo = BookPersonnelVo.builder()
                    .userId(userInfo.getUserId())
                    .realName(userInfo.getRealName())
                    .organizeName(userInfo.getOrganizeName())
                    .positionName(userInfo.getPositionName())
                    .mobilePhone(userInfo.getMobilePhone())
                    .accountStatus(0)  // 默认未封账
                    .transferTag("")    // 默认无离组借调标签
                    .build();
            result.add(personnelVo);
        }

        log.info("获取考勤本配置人员列表成功，bookConfigId: {}, 人员数: {}", bookConfigId, result.size());
        return result;
    }

    /**
     * 更新考勤本时：若已存在考勤记录，则不允许变更使用范围（范围类型、组织、成员）
     */
    private void validateScopeChangeWhenRecordsExist(String bookId, Integer oldScope, Integer newScope,
                                                     AttendanceBookConfigDto configDto) throws HandleException {
        MutablePair<List<String>, List<String>> oldScopeData = ruleScopeUtil.selectScopeList(
                bookId, ScopeBizType.ATTENDANCE_BOOK);
        if (!isScopeChanged(oldScope, newScope, oldScopeData, configDto)) {
            return;
        }
        if (hasBookRecords(bookId)) {
            throw new HandleException(AttendanceConstant.ERR_BOOK_SCOPE_CHANGE_HAS_RECORDS);
        }
    }

    /**
     * 判断使用范围是否发生变更（范围类型、组织列表、成员列表）
     */
    private boolean isScopeChanged(Integer oldScope, Integer newScope,
                                   MutablePair<List<String>, List<String>> oldScopeData,
                                   AttendanceBookConfigDto configDto) {
        if (!Objects.equals(oldScope, newScope)) {
            return true;
        }
        if (ConstantUtil.SCOPE_ALL.equals(newScope)) {
            return false;
        }
        Set<String> oldOrgs = toNormalizedIdSet(oldScopeData != null ? oldScopeData.getLeft() : null);
        Set<String> newOrgs = toNormalizedIdSet(configDto.getOrganizeList());
        Set<String> oldUsers = toNormalizedIdSet(oldScopeData != null ? oldScopeData.getRight() : null);
        Set<String> newUsers = toNormalizedIdSet(configDto.getUserIdList());
        return !oldOrgs.equals(newOrgs) || !oldUsers.equals(newUsers);
    }

    private Set<String> toNormalizedIdSet(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptySet();
        }
        return ids.stream()
                .filter(StringUtils::isNotBlank)
                .map(String::trim)
                .collect(Collectors.toSet());
    }

    /**
     * 考勤本下是否已有考勤记录
     */
    private boolean hasBookRecords(String bookId) {
        Long count = attendanceBookRecordMapper.selectCount(
                new LambdaQueryWrapper<AttendanceBookRecordEntity>()
                        .eq(AttendanceBookRecordEntity::getBookId, bookId));
        return count != null && count > 0;
    }

    /**
     * 需求1：校验考勤本名称是否重复
     *
     * @param excludeId 排除的ID（更新时使用，新增时传null）
     * @param bookName  考勤本名称
     * @throws HandleException 如果名称重复则抛出异常
     */
    private void validateBookNameDuplicate(String excludeId, String bookName) throws HandleException {
        if (StringUtils.isBlank(bookName)) {
            return;
        }

        LambdaQueryWrapper<AttendanceBookConfigEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AttendanceBookConfigEntity::getBookName, bookName)
                .eq(AttendanceBookConfigEntity::getDeleteMark, ConstantUtil.NUM_FALSE);

        // 如果是更新操作，排除当前记录
        if (StringUtils.isNotBlank(excludeId)) {
            queryWrapper.ne(AttendanceBookConfigEntity::getId, excludeId);
        }

        long count = this.count(queryWrapper);
        if (count > 0) {
            throw new HandleException(AttendanceConstant.ERR_BOOK_NAME_EXISTS);
        }
    }
}
