package com.ygtx.gxt.task;

import com.ygtx.common.core.domain.entity.SysUser;
import com.ygtx.common.core.domain.model.LoginUser;
import com.ygtx.common.utils.DateUtils;
import com.ygtx.common.utils.SecurityUtils;
import com.ygtx.framework.web.service.SysPermissionService;
import com.ygtx.gxt.domain.*;
import com.ygtx.gxt.service.*;
import com.ygtx.system.mapper.SysUserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 工单评分回退任务
 * 用于回退之前执行的运行得分和停机扣分操作（不回退工单得分）
 * 支持按时间段、按日期、按月份以及回退全部历史数据
 *
 * @author ouyj
 * @date 2026-02-12
 */
@EnableScheduling
@Component("orderScoreRollbackTask")
public class OrderScoreRollbackTask {

    private static final Logger log = LoggerFactory.getLogger(OrderScoreRollbackTask.class);

    @Autowired
    private IGxtOrderScoreDetailService orderScoreDetailService;

    @Autowired
    private IGxtRepairOrderService repairOrderService;

    @Autowired
    private IGxtWorkOrderService workOrderService;

    @Autowired
    private IGxtMonthScoreService monthScoreService;

    @Autowired
    private IGxtUserScoreService userScoreService;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysPermissionService permissionService;

    // 限制每次处理的最大记录数，防止数据量过大导致性能问题
    private static final int MAX_RECORDS_PER_PROCESS = 100;

    /**
     * 按天回退评分任务
     * 回退指定日期的所有评分操作
     * 
     * @param targetDate 目标日期
     */
   /* public void rollbackOrderScoresByDate(Date targetDate) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(targetDate);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date startTime = cal.getTime();
        
        cal.add(Calendar.DAY_OF_MONTH, 1);
        Date endTime = cal.getTime();
        
        rollbackOrderScores(startTime, endTime);
    }*/

    /**
     * 按月回退评分任务
     * 回退指定月份的所有评分操作
     * 
     * @param year 年份
     * @param month 月份 (1-12)
     */
   /* public void rollbackOrderScoresByMonth(int year, int month) {
        Calendar cal = Calendar.getInstance();
        cal.set(year, month - 1, 1, 0, 0, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date startTime = cal.getTime();
        
        cal.add(Calendar.MONTH, 1);
        Date endTime = cal.getTime();
        
        rollbackOrderScores(startTime, endTime);
    }*/


    /**
     * 定时任务：每日回退前一天的数据
     * 通常在每天凌晨执行，回退前一天的运行得分和停机扣分
     */
    //@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行
    /*public void rollbackPreviousDayData() {
        log.info("开始执行每日数据回退任务");
        
        // 获取昨天的日期
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_MONTH, -1);
        Date yesterday = cal.getTime();
        
        rollbackOrderScoresByDate(yesterday);
    }*/

    /**
     * 定时任务：每月回退上个月的数据
     * 通常在每月1日凌晨执行，回退上个月的运行得分和停机扣分
     */
    //@Scheduled(cron = "0 0 2 1 * ?") // 每月1日凌晨2点执行
    /*public void rollbackPreviousMonthData() {
        log.info("开始执行每月数据回退任务");
        
        // 获取上个月的年份和月份
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MONTH, -1);
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1; // Calendar.MONTH是从0开始的
        
        rollbackOrderScoresByMonth(year, month);
    }*/

    /**
     * 定时任务：回退全部历史数据
     */
    public void scheduledRollbackAllHistoricalData() {
        log.info("开始执行全部历史数据回退任务");
        rollbackAllHistoricalData();
    }

    /**
     * 回退当前日期及之前的所有数据
     * 回退从系统最早记录到当前时间的所有运行得分和停机扣分数据
     */
    public void rollbackAllHistoricalData() {
        log.info("开始回退当前日期及之前的所有运行得分和停机扣分数据");

        // 设置开始时间为很久以前（比如1970年1月1日）
        Calendar cal = Calendar.getInstance();
        cal.set(1970, Calendar.JANUARY, 1, 0, 0, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date startTime = cal.getTime();

        // 结束时间为当前时间
        Date endTime = new Date();

        rollbackOrderScores(startTime, endTime);
    }

    /**
     * 回退指定工单的评分
     * 
     * @param orderId 工单ID
     * @param orderType 工单类型：1-维修工单，2-维保工单
     */
    /*public void rollbackOrderByOrderId(Long orderId, Integer orderType) {
        log.info("开始回退工单ID {} 的评分操作", orderId);
        
        setSystemUserContext();
        
        try {
            // 查询该工单的所有评分明细记录
            GxtOrderScoreDetail queryDetail = new GxtOrderScoreDetail();
            queryDetail.setOrderId(orderId);
            queryDetail.setOrderType(orderType);
            
            List<GxtOrderScoreDetail> scoreDetails = orderScoreDetailService.selectGxtOrderScoreDetailList(queryDetail);
            
            if (scoreDetails.isEmpty()) {
                log.warn("工单ID {} 没有找到评分明细记录", orderId);
                return;
            }
            
            // 执行回退操作
            rollbackOrderScore(orderId, scoreDetails);
            
            log.info("工单ID {} 的评分回退完成", orderId);
        } catch (Exception e) {
            log.error("回退工单ID {} 评分时发生异常", orderId, e);
        }
    }*/

    /**
     * 执行工单评分回退任务
     * 回退指定时间段内的所有评分操作
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     */
    public void rollbackOrderScores(Date startTime, Date endTime) {
        log.info("开始执行工单评分回退任务，时间范围: {} - {}", 
            DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", startTime),
            DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", endTime));

        // 参数验证
        if (startTime == null || endTime == null) {
            log.error("开始时间或结束时间不能为空");
            return;
        }
        
        if (startTime.after(endTime)) {
            log.error("开始时间不能晚于结束时间");
            return;
        }

        // 设置系统用户上下文
        setSystemUserContext();

        try {
            // 查询指定时间范围内的所有评分明细记录
            List<GxtOrderScoreDetail> scoreDetails = queryScoreDetailsByTimeRange(startTime, endTime);
            
            if (scoreDetails.isEmpty()) {
                log.info("在指定时间范围内没有找到需要回退的评分记录");
                return;
            }

            log.info("找到 {} 条需要回退的评分记录", scoreDetails.size());

            // 按工单分组处理
            Map<String, List<GxtOrderScoreDetail>> orderGroupedDetails = groupByOrderKey(scoreDetails);
            
            int processedCount = 0;
            int errorCount = 0;
            
            for (Map.Entry<String, List<GxtOrderScoreDetail>> entry : orderGroupedDetails.entrySet()) {
                try {
                    // 从复合键中解析出orderId
                    String orderKey = entry.getKey();
                    String[] parts = orderKey.split("_");
                    Long orderId = Long.parseLong(parts[0]);
                    
                    rollbackOrderScore(orderId, entry.getValue());
                    processedCount++;
                } catch (Exception e) {
                    log.error("回退工单键 {} 的评分时发生异常", entry.getKey(), e);
                    errorCount++;
                }
            }

            log.info("工单评分回退任务执行完成，成功处理 {} 个工单，失败 {} 个工单", 
                processedCount, errorCount);
        } catch (Exception e) {
            log.error("执行工单评分回退任务时发生异常", e);
        }
    }

    /**
     * 根据时间范围查询评分明细记录
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 评分明细记录列表
     */
    private List<GxtOrderScoreDetail> queryScoreDetailsByTimeRange(Date startTime, Date endTime) {
        // 这里需要根据实际的Mapper实现来调整查询逻辑
        // 可能需要在GxtOrderScoreDetailMapper.xml中添加时间范围查询
        GxtOrderScoreDetail queryDetail = new GxtOrderScoreDetail();
        queryDetail.setStatus(0);
        List<GxtOrderScoreDetail> allDetails = orderScoreDetailService.selectGxtOrderScoreDetailList(queryDetail);
        
        List<GxtOrderScoreDetail> filteredDetails = new ArrayList<>();
        for (GxtOrderScoreDetail detail : allDetails) {
            if (detail.getScoreType() == 2 || detail.getScoreType() == 3) {
                if (detail.getCreateTime() != null &&
                        detail.getCreateTime().compareTo(startTime) >= 0 &&
                        detail.getCreateTime().compareTo(endTime) <= 0) {
                    filteredDetails.add(detail);
                }
            }
        }
        /*
        // 如果数据量很大，可能需要分页处理
        if (filteredDetails.size() > MAX_RECORDS_PER_PROCESS) {
            log.warn("找到 {} 条记录，超过最大处理限制 {}，将只处理前 {} 条", 
                filteredDetails.size(), MAX_RECORDS_PER_PROCESS, MAX_RECORDS_PER_PROCESS);
            return filteredDetails.subList(0, MAX_RECORDS_PER_PROCESS);
        }*/
        
        return filteredDetails;
    }

    /**
     * 回退指定工单的所有评分操作
     * 
     * @param orderId 工单ID
     * @param scoreDetails 该工单的评分明细记录
     */
    private void rollbackOrderScore(Long orderId, List<GxtOrderScoreDetail> scoreDetails) {
        if (scoreDetails == null || scoreDetails.isEmpty()) {
            log.warn("工单ID {} 没有待回退的评分记录", orderId);
            return;
        }

        // 获取第一条记录来判断工单类型
        GxtOrderScoreDetail firstDetail = scoreDetails.get(0);
        Integer orderType = firstDetail.getOrderType();
        String orderCode = firstDetail.getOrderCode();

        log.info("开始回退工单 {} (ID: {}) 的评分操作，共 {} 条记录", orderCode, orderId, scoreDetails.size());

        // 记录回退前的状态用于日志
        //logOriginalScores(orderId, orderType, scoreDetails);

        try {
            if (orderType == 1) {
                // 维修工单回退
                rollbackRepairOrderScore(orderId, scoreDetails);
            } else if (orderType == 2) {
                // 维保工单回退
                rollbackWorkOrderScore(orderId, scoreDetails);
            } else {
                log.warn("不支持的工单类型: {}", orderType);
                return;
            }

            // 删除评分明细记录
            int deletedCount = 0;
            for (GxtOrderScoreDetail detail : scoreDetails) {
                try {
                    orderScoreDetailService.deleteGxtOrderScoreDetailById(detail.getId());
                    deletedCount++;
                } catch (Exception e) {
                    log.error("删除评分明细记录 ID {} 时发生异常", detail.getId(), e);
                }
            }

            log.info("工单 {} 的评分回退完成，共删除 {} 条明细记录", orderCode, deletedCount);
        } catch (Exception e) {
            log.error("回退工单 {} 评分时发生异常", orderCode, e);
            throw new RuntimeException("工单评分回退失败: " + orderCode, e);
        }
    }

    /**
     * 记录回退前的原始分数状态（仅显示运行得分和停机扣分）
     * 
     * @param orderId 工单ID
     * @param orderType 工单类型
     * @param scoreDetails 评分明细记录
     */
    private void logOriginalScores(Long orderId, Integer orderType, List<GxtOrderScoreDetail> scoreDetails) {
        StringBuilder sb = new StringBuilder();
        sb.append("回退前的原始分数状态(仅运行分和停机分):\n");
        
        for (GxtOrderScoreDetail detail : scoreDetails) {
            sb.append(String.format("  用户: %s, 类型: %d, 运行分: %s, 停机分: %s\n",
                detail.getNickName(),
                detail.getScoreType(),
                detail.getRunScore(),
                detail.getStopScore()));
        }
        
        log.info(sb.toString());
    }

    /**
     * 回退维修工单评分
     * 
     * @param orderId 工单ID
     * @param scoreDetails 评分明细记录
     */
    private void rollbackRepairOrderScore(Long orderId, List<GxtOrderScoreDetail> scoreDetails) {
        // 查询工单信息
        GxtRepairOrder repairOrder = repairOrderService.selectGxtRepairOrderById(orderId);
        if (repairOrder == null) {
            log.warn("未找到维修工单 ID: {}", orderId);
            return;
        }

        // 查询工单人员列表
        List<GxtRepairOrderPerson> persons = repairOrderService.selectRepairOrderPersonListByOrderId(orderId);
        if (persons == null || persons.isEmpty()) {
            log.warn("维修工单 {} 没有找到相关人员", repairOrder.getWorkOrderProjectNo());
            return;
        }

        // 按人员分组统计需要回退的分数
        Map<Long, ScoreRollbackInfo> personScoreMap = calculatePersonRollbackScores(scoreDetails, persons);

        // 回退人员得分
        rollbackPersonScores(persons, personScoreMap, 1);

        // 回退月度统计数据（传入评分明细列表以便按创建时间分组）
        rollbackMonthlyScoreData(scoreDetails, personScoreMap);

        log.info("维修工单 {} 人员得分回退完成", repairOrder.getWorkOrderProjectNo());
    }

    /**
     * 回退维保工单评分
     * 
     * @param orderId 工单ID
     * @param scoreDetails 评分明细记录
     */
    private void rollbackWorkOrderScore(Long orderId, List<GxtOrderScoreDetail> scoreDetails) {
        // 查询工单信息
        GxtWorkOrder workOrder = workOrderService.selectGxtWorkOrderById(orderId);
        if (workOrder == null) {
            log.warn("未找到维保工单 ID: {}", orderId);
            return;
        }

        // 查询工单人员列表
        List<GxtWorkOrderPerson> persons = workOrderService.selectWorkOrderPersonListByOrderId(orderId);
        if (persons == null || persons.isEmpty()) {
            log.warn("维保工单 {} 没有找到相关人员", workOrder.getWorkOrderProjectNo());
            return;
        }

        // 按人员分组统计需要回退的分数
        Map<Long, ScoreRollbackInfo> personScoreMap = calculatePersonRollbackScores(scoreDetails, persons);

        // 回退人员得分
        rollbackPersonScores(persons, personScoreMap, 2);

        // 回退月度统计数据（传入评分明细列表以便按创建时间分组）
        rollbackMonthlyScoreData(scoreDetails, personScoreMap);

        log.info("维保工单 {} 人员得分回退完成", workOrder.getWorkOrderProjectNo());
    }

    /**
     * 计算每个人员需要回退的分数
     * 
     * @param scoreDetails 评分明细记录
     * @param persons 工单人员列表
     * @return 人员ID -> 回退分数信息的映射
     */
    private Map<Long, ScoreRollbackInfo> calculatePersonRollbackScores(
            List<GxtOrderScoreDetail> scoreDetails, List<? extends Object> persons) {
        
        Map<Long, ScoreRollbackInfo> personScoreMap = new HashMap<>();
        
        // 初始化每个人的回退信息
        for (Object personObj : persons) {
            Long userId = null;
            String nickName = null;
            
            if (personObj instanceof GxtRepairOrderPerson) {
                GxtRepairOrderPerson person = (GxtRepairOrderPerson) personObj;
                userId = person.getUserId();
                nickName = person.getNickName();
            } else if (personObj instanceof GxtWorkOrderPerson) {
                GxtWorkOrderPerson person = (GxtWorkOrderPerson) personObj;
                userId = person.getUserId();
                nickName = person.getNickName();
            }
            
            if (userId != null) {
                personScoreMap.put(userId, new ScoreRollbackInfo(nickName));
            }
        }

        // 统计每个人的各类分数回退值（只回退运行得分和停机扣分，不回退工单得分）
        for (GxtOrderScoreDetail detail : scoreDetails) {
            Long userId = detail.getUserId();
            ScoreRollbackInfo scoreInfo = personScoreMap.get(userId);
            
            if (scoreInfo != null) {
                // 直接累加原始分数值（回退时应该用正值抵消）
                // 注意：不处理rateScore（工单得分）的回退
                if (detail.getRunScore() != null) {
                    BigDecimal originalRunScore = detail.getRunScore();
                    scoreInfo.runScore = scoreInfo.runScore.add(originalRunScore);
                    log.debug("人员 {} 全局运行得分回退计算: 原始={}，累计回退={}", 
                        detail.getNickName(), originalRunScore, scoreInfo.runScore);
                }
                if (detail.getStopScore() != null) {
                    BigDecimal originalStopScore = detail.getStopScore();
                    scoreInfo.stopScore = scoreInfo.stopScore.add(originalStopScore);
                    log.debug("人员 {} 全局停机得分回退计算: 原始={}，累计回退={}", 
                        detail.getNickName(), originalStopScore, scoreInfo.stopScore);
                }
                // 总分回退只包含运行得分和停机扣分的变化
                BigDecimal runScoreChange = detail.getRunScore() != null ? detail.getRunScore() : BigDecimal.ZERO;
                BigDecimal stopScoreChange = detail.getStopScore() != null ? detail.getStopScore() : BigDecimal.ZERO;
                scoreInfo.totalScore = scoreInfo.totalScore.add(runScoreChange).add(stopScoreChange);
                log.debug("人员 {} 全局总分回退计算: 运行变化={}，停机变化={}，总变化={}", 
                    detail.getNickName(), runScoreChange, stopScoreChange, scoreInfo.totalScore);
            }
        }

        return personScoreMap;
    }

    /**
     * 回退人员得分
     * 
     * @param persons 工单人员列表
     * @param personScoreMap 人员回退分数映射
     * @param orderType 工单类型：1-维修工单，2-维保工单
     */
    private void rollbackPersonScores(List<? extends Object> persons, 
                                     Map<Long, ScoreRollbackInfo> personScoreMap, 
                                     int orderType) {
        List<Object> updatedPersons = new ArrayList<>();
        
        for (Object personObj : persons) {
            Long userId = null;
            if (personObj instanceof GxtRepairOrderPerson) {
                userId = ((GxtRepairOrderPerson) personObj).getUserId();
            } else if (personObj instanceof GxtWorkOrderPerson) {
                userId = ((GxtWorkOrderPerson) personObj).getUserId();
            }
            
            ScoreRollbackInfo scoreInfo = personScoreMap.get(userId);
            if (scoreInfo != null) {
                // 创建更新对象
                if (orderType == 1) {
                    GxtRepairOrderPerson person = (GxtRepairOrderPerson) personObj;
                    GxtRepairOrderPerson updatedPerson = new GxtRepairOrderPerson();
                    updatedPerson.setId(person.getId());
                    
                    // 只回退运行得分和停机扣分，保留工单得分不变
                    Double currentRunScore = person.getRunScore() != null ? person.getRunScore() : 0.0;
                    Double currentStopScore = person.getStopScore() != null ? person.getStopScore() : 0.0;
                    BigDecimal currentScore = person.getScore() != null ? person.getScore() : BigDecimal.ZERO;
                    
                    // 回退运行得分和停机扣分（注意：这里是减法，因为是回退操作）
                    double runScoreToSubtract = scoreInfo.runScore.doubleValue();
                    double stopScoreToSubtract = scoreInfo.stopScore.doubleValue();
                    
                    updatedPerson.setRunScore(currentRunScore - runScoreToSubtract);
                    updatedPerson.setStopScore(currentStopScore - stopScoreToSubtract);
                    // 总分回退只包含运行得分和停机扣分的变化
                    updatedPerson.setScore(currentScore.subtract(scoreInfo.totalScore));
                    updatedPerson.setUpdateBy(SecurityUtils.getLoginUser().getUser().getUserName());
                    updatedPerson.setUpdateTime(new Date());
                    
                    updatedPersons.add(updatedPerson);
                    
                    log.info("维修工单人员 {} 得分回退详情: " +
                        "当前运行分={}, 回退运行分={}, 实际运行分={}; " +
                        "当前停机分={}, 回退停机分={}, 实际停机分={}; " +
                        "当前总分={}, 回退总分={}, 实际总分={}", 
                        scoreInfo.nickName,
                        currentRunScore, runScoreToSubtract, updatedPerson.getRunScore(),
                        currentStopScore, stopScoreToSubtract, updatedPerson.getStopScore(),
                        currentScore, scoreInfo.totalScore, updatedPerson.getScore());
                        
                } else if (orderType == 2) {
                    GxtWorkOrderPerson person = (GxtWorkOrderPerson) personObj;
                    GxtWorkOrderPerson updatedPerson = new GxtWorkOrderPerson();
                    updatedPerson.setId(person.getId());
                    
                    // 只回退运行得分和停机扣分，保留工单得分不变
                    Double currentRunScore = person.getRunScore() != null ? person.getRunScore() : 0.0;
                    Double currentStopScore = person.getStopScore() != null ? person.getStopScore() : 0.0;
                    BigDecimal currentScore = person.getScore() != null ? person.getScore() : BigDecimal.ZERO;
                    
                    // 回退运行得分和停机扣分（注意：这里是减法，因为是回退操作）
                    double runScoreToSubtract = scoreInfo.runScore.doubleValue();
                    double stopScoreToSubtract = scoreInfo.stopScore.doubleValue();
                    
                    updatedPerson.setRunScore(currentRunScore - runScoreToSubtract);
                    updatedPerson.setStopScore(currentStopScore - stopScoreToSubtract);
                    // 总分回退只包含运行得分和停机扣分的变化
                    updatedPerson.setScore(currentScore.subtract(scoreInfo.totalScore));
                    updatedPerson.setUpdateBy(SecurityUtils.getLoginUser().getUser().getUserName());
                    updatedPerson.setUpdateTime(new Date());
                    
                    updatedPersons.add(updatedPerson);
                    
                    log.info("维保工单人员 {} 得分回退详情: " +
                        "当前运行分={}, 回退运行分={}, 实际运行分={}; " +
                        "当前停机分={}, 回退停机分={}, 实际停机分={}; " +
                        "当前总分={}, 回退总分={}, 实际总分={}", 
                        scoreInfo.nickName,
                        currentRunScore, runScoreToSubtract, updatedPerson.getRunScore(),
                        currentStopScore, stopScoreToSubtract, updatedPerson.getStopScore(),
                        currentScore, scoreInfo.totalScore, updatedPerson.getScore());
                }
            }
        }

        // 批量更新人员得分
        if (!updatedPersons.isEmpty()) {
            if (orderType == 1) {
                List<GxtRepairOrderPerson> repairPersons = new ArrayList<>();
                for (Object obj : updatedPersons) {
                    repairPersons.add((GxtRepairOrderPerson) obj);
                }
                repairOrderService.updateRepairOrderPersonList(repairPersons);
            } else if (orderType == 2) {
                List<GxtWorkOrderPerson> workPersons = new ArrayList<>();
                for (Object obj : updatedPersons) {
                    workPersons.add((GxtWorkOrderPerson) obj);
                }
                workOrderService.updateWorkOrderPersonList(workPersons);
            }
            log.info("共回退 {} 名人员的得分", updatedPersons.size());
        }
    }

    /**
     * 回退月度统计数据
     * 注意：这里需要按每条评分明细的创建时间来回退，而不是工单创建时间
     * 
     * @param scoreDetails 评分明细列表（包含创建时间信息）
     * @param personScoreMap 人员回退分数映射
     */
    private void rollbackMonthlyScoreData(List<GxtOrderScoreDetail> scoreDetails,
                                         Map<Long, ScoreRollbackInfo> personScoreMap) {
        try {
            // 按月份分组处理，因为每条评分明细可能属于不同的月份
            Map<String, List<GxtOrderScoreDetail>> monthlyGroups = new HashMap<>();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
            
            // 按创建时间分组
            for (GxtOrderScoreDetail detail : scoreDetails) {
                String monthPeriod = sdf.format(detail.getCreateTime());
                monthlyGroups.computeIfAbsent(monthPeriod, k -> new ArrayList<>()).add(detail);
            }
            
            // 逐月处理回退
            for (Map.Entry<String, List<GxtOrderScoreDetail>> entry : monthlyGroups.entrySet()) {
                String monthPeriod = entry.getKey();
                List<GxtOrderScoreDetail> monthlyDetails = entry.getValue();
                
                // 为当前月份重新计算人员回退分数（避免跨月数据污染）
                Map<Long, ScoreRollbackInfo> monthlyPersonScoreMap = calculateMonthlyPersonRollbackScores(monthlyDetails);
                
                if (monthlyPersonScoreMap.isEmpty()) {
                    log.debug("月份 {} 没有需要回退的人员记录", monthPeriod);
                    continue;
                }
                
                // 从第一条记录获取工单信息，进而获取部门信息
                GxtOrderScoreDetail firstDetail = monthlyDetails.get(0);
                Long orderId = firstDetail.getOrderId();
                Integer orderType = firstDetail.getOrderType();
                
                Long deptId = null;
                if (orderType == 1) {
                    // 维修工单
                    GxtRepairOrder repairOrder = repairOrderService.selectGxtRepairOrderById(orderId);
                    if (repairOrder != null) {
                        deptId = repairOrder.getPcsStationPid();
                    }
                } else if (orderType == 2) {
                    // 维保工单
                    GxtWorkOrder workOrder = workOrderService.selectGxtWorkOrderById(orderId);
                    if (workOrder != null) {
                        deptId = workOrder.getPcsStationPid();
                    }
                }
                
                if (deptId == null) {
                    log.warn("无法获取部门信息，跳过月度统计回退: 月份={}，记录数={}", monthPeriod, monthlyDetails.size());
                    continue;
                }
                
                // 获取该月份的月度统计信息
                GxtMonthScore queryScore = new GxtMonthScore();
                queryScore.setDeptId(deptId);
                queryScore.setMonthPeriod(monthPeriod);
                List<GxtMonthScore> scoreList = monthScoreService.selectGxtMonthScoreList(queryScore);
                
                if (scoreList.isEmpty()) {
                    log.warn("未找到月度统计数据: 部门ID={}, 月份={}", deptId, monthPeriod);
                    continue;
                }
                
                GxtMonthScore monthScore = scoreList.get(0);
                
                // 回退该月份涉及的用户评分统计
                rollbackUserScores(monthScore, monthlyPersonScoreMap, orderType);
                
                log.info("已完成月份 {} 的月度统计回退，部门ID: {}", monthPeriod, deptId);
            }


        } catch (Exception e) {
            log.error("回退月度统计数据时发生异常", e);
        }
    }

    /**
     * 回退用户评分统计
     * 
     * @param monthScore 月度统计信息
     * @param personScoreMap 人员回退分数映射
     * @param orderType 工单类型
     */
    private void rollbackUserScores(GxtMonthScore monthScore, 
                                   Map<Long, ScoreRollbackInfo> personScoreMap, 
                                   int orderType) {
        try {
            for (Map.Entry<Long, ScoreRollbackInfo> entry : personScoreMap.entrySet()) {
                Long userId = entry.getKey();
                ScoreRollbackInfo scoreInfo = entry.getValue();
                
                SysUser sysUser = userMapper.selectUserById(userId);
                if (sysUser == null) {
                    continue;
                }
                
                // 使用userName、monthPeriod、monthScoreId精确查询用户评分记录
                GxtUserScore userScoreQuery = new GxtUserScore();
                userScoreQuery.setUserName(sysUser.getUserName());
                userScoreQuery.setMonthPeriod(monthScore.getMonthPeriod());
                userScoreQuery.setMonthScoreId(monthScore.getId());
                List<GxtUserScore> userScores = userScoreService.selectGxtUserScoreList(userScoreQuery);
                
                if (!userScores.isEmpty()) {
                    // 找到现有记录，进行回退更新
                    GxtUserScore userScore = userScores.get(0);
                    
                    if (orderType == 1) {
                        // 维修工单：只回退运行得分和停机扣分相关的部分
                        BigDecimal currentRepairTotal = (userScore.getRepairTotalScore() != null) ?
                                userScore.getRepairTotalScore() : BigDecimal.ZERO;
                        // 总分回退只包含运行得分和停机扣分的变化（注意：这里是减法）
                        BigDecimal newRepairScore = currentRepairTotal.subtract(scoreInfo.totalScore);
                        userScore.setRepairTotalScore(newRepairScore);
                        
                        // 更新最终评分
                        BigDecimal maintenanceScore = (userScore.getMaintenanceTotalScore() != null) ?
                                userScore.getMaintenanceTotalScore() : BigDecimal.ZERO;
                        BigDecimal finalScore = maintenanceScore.add(newRepairScore);
                        userScore.setFinalScore(finalScore);
                        
                    } else if (orderType == 2) {
                        // 维保工单：只回退运行得分和停机扣分相关的部分
                        BigDecimal currentMaintenanceTotal = (userScore.getMaintenanceTotalScore() != null) ?
                                userScore.getMaintenanceTotalScore() : BigDecimal.ZERO;
                        // 总分回退只包含运行得分和停机扣分的变化（注意：这里是减法）
                        BigDecimal newMaintenanceScore = currentMaintenanceTotal.subtract(scoreInfo.totalScore);
                        userScore.setMaintenanceTotalScore(newMaintenanceScore);
                        
                        // 更新最终评分
                        BigDecimal repairScore = (userScore.getRepairTotalScore() != null) ?
                                userScore.getRepairTotalScore() : BigDecimal.ZERO;
                        BigDecimal finalScore = repairScore.add(newMaintenanceScore);
                        userScore.setFinalScore(finalScore);
                    }
                    
                    userScore.setUpdateBy(SecurityUtils.getLoginUser().getUser().getUserName());
                    userScore.setUpdateTime(new Date());
                    userScoreService.updateGxtUserScore(userScore);
                    
                    log.debug("回退用户 {} 月度统计得分: {} -> {}", 
                        sysUser.getUserName(), 
                        userScore.getFinalScore().subtract(scoreInfo.totalScore), 
                        userScore.getFinalScore());
                }
            }
        } catch (Exception e) {
            log.error("回退用户评分统计时发生异常", e);
        }
    }

    /**
     * 计算指定月份内每个人员需要回退的分数
     * 
     * @param monthlyDetails 指定月份的评分明细记录
     * @return 人员ID -> 回退分数信息的映射
     */
    private Map<Long, ScoreRollbackInfo> calculateMonthlyPersonRollbackScores(
            List<GxtOrderScoreDetail> monthlyDetails) {
        
        Map<Long, ScoreRollbackInfo> monthlyPersonScoreMap = new HashMap<>();
        
        // 统计每个月份内每个人的各类分数回退值
        for (GxtOrderScoreDetail detail : monthlyDetails) {
            Long userId = detail.getUserId();
            String nickName = detail.getNickName();
            
            // 初始化人员信息
            ScoreRollbackInfo scoreInfo = monthlyPersonScoreMap.computeIfAbsent(userId, 
                k -> new ScoreRollbackInfo(nickName));
            
            // 直接累加原始分数值（回退时应该用正值抵消）
            if (detail.getRunScore() != null) {
                BigDecimal originalRunScore = detail.getRunScore();
                scoreInfo.runScore = scoreInfo.runScore.add(originalRunScore);
                log.debug("人员 {} 运行得分回退计算: 原始={}，累计回退={}", 
                    nickName, originalRunScore, scoreInfo.runScore);
            }
            if (detail.getStopScore() != null) {
                BigDecimal originalStopScore = detail.getStopScore();
                scoreInfo.stopScore = scoreInfo.stopScore.add(originalStopScore);
                log.debug("人员 {} 停机得分回退计算: 原始={}，累计回退={}", 
                    nickName, originalStopScore, scoreInfo.stopScore);
            }
            // 总分回退只包含运行得分和停机扣分的变化
            BigDecimal runScoreChange = detail.getRunScore() != null ? detail.getRunScore() : BigDecimal.ZERO;
            BigDecimal stopScoreChange = detail.getStopScore() != null ? detail.getStopScore() : BigDecimal.ZERO;
            scoreInfo.totalScore = scoreInfo.totalScore.add(runScoreChange).add(stopScoreChange);
            log.debug("人员 {} 月度总分回退计算: 运行变化={}，停机变化={}，总变化={}", 
                nickName, runScoreChange, stopScoreChange, scoreInfo.totalScore);
        }
        
        return monthlyPersonScoreMap;
    }

    /**
     * 按工单ID和类型组合分组评分明细记录
     * 使用orderId+orderType作为复合键，避免维修工单和维保工单ID冲突
     * 
     * @param scoreDetails 评分明细记录列表
     * @return 复合键(orderId_orderType) -> 评分明细列表的映射
     */
    private Map<String, List<GxtOrderScoreDetail>> groupByOrderKey(List<GxtOrderScoreDetail> scoreDetails) {
        Map<String, List<GxtOrderScoreDetail>> grouped = new HashMap<>();
        for (GxtOrderScoreDetail detail : scoreDetails) {
            // 使用orderId和orderType组合作为唯一键
            String orderKey = detail.getOrderId() + "_" + detail.getOrderType();
            grouped.computeIfAbsent(orderKey, k -> new ArrayList<>()).add(detail);
        }
        return grouped;
    }

    /**
     * 设置系统用户上下文，用于自动操作
     */
    private void setSystemUserContext() {
        try {
            // 获取admin用户信息
            SysUser userAdmin = userMapper.selectUserByUserName("admin");
            if (userAdmin != null) {
                Set<String> permissions = permissionService.getMenuPermission(userAdmin);
                LoginUser loginUser = new LoginUser(userAdmin, permissions);

                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        loginUser,
                        null,
                        loginUser.getAuthorities()
                );

                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception e) {
            log.error("设置系统用户上下文失败", e);
        }
    }

    /**
     * 人员得分回退信息类
     */
    private static class ScoreRollbackInfo {
        String nickName;
        BigDecimal runScore = BigDecimal.ZERO;
        BigDecimal stopScore = BigDecimal.ZERO;
        BigDecimal totalScore = BigDecimal.ZERO;
        
        public ScoreRollbackInfo(String nickName) {
            this.nickName = nickName;
        }
    }

}