package org.xyzh.study.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.enums.AchievementEventType;
import org.xyzh.common.core.event.AchievementEvent;
import org.xyzh.common.core.page.PageDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.dto.study.TbLearningHistory;
import org.xyzh.common.dto.user.TbSysUser;
import org.xyzh.common.utils.IDUtils;
import org.xyzh.common.vo.LearningHistoryVO;
import org.xyzh.common.vo.LearningStatisticsDetailVO;
import org.xyzh.common.vo.LearningStatisticsVO;
import org.xyzh.study.mapper.LearningHistoryMapper;
import org.xyzh.study.service.SCLearningHistoryService;
import org.xyzh.system.utils.LoginUtil;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description 学习历史服务实现类
 * @filename SCLearningHistoryServiceImpl.java
 * @author yslg
 * @copyright xyzh
 * @since 2025-10-27
 */
@Service
public class SCLearningHistoryServiceImpl implements SCLearningHistoryService {

    private static final Logger logger = LoggerFactory.getLogger(SCLearningHistoryServiceImpl.class);

    @Autowired
    private LearningHistoryMapper learningHistoryMapper;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional
    public ResultDomain<TbLearningHistory> recordLearningHistory(TbLearningHistory learningHistory) {
        ResultDomain<TbLearningHistory> resultDomain = new ResultDomain<>();
        
        try {
            // 参数校验
            if (learningHistory.getUserID() == null || learningHistory.getUserID().isEmpty()) {
                TbSysUser currentUser = LoginUtil.getCurrentUser();
                if (currentUser == null) {
                    resultDomain.fail("用户未登录");
                    return resultDomain;
                }
                learningHistory.setUserID(currentUser.getID());
            }

            if (learningHistory.getResourceType() == null) {
                resultDomain.fail("资源类型不能为空");
                return resultDomain;
            }

            if (learningHistory.getStartTime() == null) {
                learningHistory.setStartTime(new Date());
            }

            // 计算时长
            if (learningHistory.getDuration() == null || learningHistory.getDuration() <= 0) {
                if (learningHistory.getEndTime() != null) {
                    long duration = (learningHistory.getEndTime().getTime() - learningHistory.getStartTime().getTime()) / 1000;
                    learningHistory.setDuration((int) duration);
                } else {
                    learningHistory.setDuration(0);
                }
            }

            // 判断是插入还是更新
            boolean isUpdate = false;
            if (learningHistory.getHistoryID() != null && !learningHistory.getHistoryID().isEmpty()) {
                isUpdate = true;
            }

            int result;
            if (isUpdate) {
                // 更新已有记录
                result = learningHistoryMapper.updateLearningHistory(learningHistory);
                if (result > 0) {
                    resultDomain.success("更新学习历史成功", learningHistory);
                    logger.info("更新学习历史成功，historyID: {}, 用户ID: {}, 资源类型: {}, 时长: {}秒", 
                        learningHistory.getHistoryID(), learningHistory.getUserID(), 
                        learningHistory.getResourceType(), learningHistory.getDuration());
                    
                    // 发布成就事件 - 学习时长更新
                    publishLearningTimeEvent(learningHistory);
                } else {
                    resultDomain.fail("更新学习历史失败");
                }
            } else {
                // 插入新记录
                learningHistory.setID(IDUtils.generateID());
                learningHistory.setHistoryID(IDUtils.generateID());
                learningHistory.setCreateTime(new Date());
                
                result = learningHistoryMapper.insertLearningHistory(learningHistory);
                if (result > 0) {
                    resultDomain.success("记录学习历史成功", learningHistory);
                    logger.info("记录学习历史成功，ID: {}, 用户ID: {}, 资源类型: {}, 时长: {}秒", 
                        learningHistory.getID(), learningHistory.getUserID(), 
                        learningHistory.getResourceType(), learningHistory.getDuration());
                } else {
                    resultDomain.fail("记录学习历史失败");
                }
            }

        } catch (Exception e) {
            logger.error("记录学习历史异常", e);
            resultDomain.fail("记录学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    @Transactional
    public ResultDomain<Boolean> batchRecordLearningHistory(List<TbLearningHistory> historyList) {
        ResultDomain<Boolean> resultDomain = new ResultDomain<>();
        
        try {
            if (historyList == null || historyList.isEmpty()) {
                resultDomain.fail("学习历史列表不能为空");
                return resultDomain;
            }

            TbSysUser currentUser = LoginUtil.getCurrentUser();
            Date now = new Date();

            for (TbLearningHistory learningHistory : historyList) {
                if (learningHistory.getUserID() == null || learningHistory.getUserID().isEmpty()) {
                    if (currentUser == null) {
                        resultDomain.fail("用户未登录");
                        return resultDomain;
                    }
                    learningHistory.setUserID(currentUser.getID());
                }
                if (learningHistory.getStartTime() == null) {
                    learningHistory.setStartTime(now);
                }
                if (learningHistory.getID() == null || learningHistory.getID().isEmpty()) {
                    learningHistory.setID(IDUtils.generateID());
                }
                if (learningHistory.getCreateTime() == null) {
                    learningHistory.setCreateTime(now);
                }
            }

            int result = learningHistoryMapper.batchInsertLearningHistories(historyList);
            if (result > 0) {
                resultDomain.success("批量记录学习历史成功", true);
                logger.info("批量记录学习历史成功，数量: {}", result);
            } else {
                resultDomain.fail("批量记录学习历史失败");
            }

        } catch (Exception e) {
            logger.error("批量记录学习历史异常", e);
            resultDomain.fail("批量记录学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<LearningHistoryVO> getLearningHistories(TbLearningHistory filter) {
        ResultDomain<LearningHistoryVO> resultDomain = new ResultDomain<>();
        
        try {
            List<LearningHistoryVO> historyVOList = learningHistoryMapper.selectLearningHistoriesWithDetails(filter);
            
            // 格式化时长
            formatDuration(historyVOList);
            
            resultDomain.success("查询学习历史成功", historyVOList);

        } catch (Exception e) {
            logger.error("查询学习历史异常", e);
            resultDomain.fail("查询学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<PageDomain<LearningHistoryVO>> getLearningHistoriesPage(PageRequest<TbLearningHistory> pageRequest) {
        ResultDomain<PageDomain<LearningHistoryVO>> resultDomain = new ResultDomain<>();
        
        try {
            TbLearningHistory filter = pageRequest.getFilter();
            if (filter == null) {
                filter = new TbLearningHistory();
            }
            
            // 分页参数
            PageParam pageParam = pageRequest.getPageParam();
            pageParam.setOffset((pageParam.getPageNumber() - 1) * pageParam.getPageSize());

            // 查询总数
            long total = learningHistoryMapper.countLearningHistories(filter);
            
            // 查询列表
            List<TbLearningHistory> historyList = learningHistoryMapper.selectLearningHistoriesPage(filter, pageParam);
            
            // 转换为VO
            List<LearningHistoryVO> historyVOList = historyList.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
            
            // 格式化时长
            formatDuration(historyVOList);

            // 构建分页结果
            PageDomain<LearningHistoryVO> pageDomain = new PageDomain<>();
            pageParam.setTotalElements(total);
            pageParam.setTotalPages((int) Math.ceil((double) total / pageParam.getPageSize()));
            pageDomain.setPageParam(pageParam);
            pageDomain.setDataList(historyVOList);

            resultDomain.success("分页查询学习历史成功", pageDomain);

        } catch (Exception e) {
            logger.error("分页查询学习历史异常", e);
            resultDomain.fail("分页查询学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<TbLearningHistory> getLearningHistoryById(String id) {
        ResultDomain<TbLearningHistory> resultDomain = new ResultDomain<>();
        
        try {
            if (id == null || id.isEmpty()) {
                resultDomain.fail("历史记录ID不能为空");
                return resultDomain;
            }

            TbLearningHistory learningHistory = learningHistoryMapper.selectById(id);
            if (learningHistory != null) {
                resultDomain.success("查询学习历史成功", learningHistory);
            } else {
                resultDomain.fail("学习历史不存在");
            }

        } catch (Exception e) {
            logger.error("查询学习历史异常", e);
            resultDomain.fail("查询学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<LearningStatisticsVO> getUserLearningStatistics(String userId, Date startTime, Date endTime) {
        ResultDomain<LearningStatisticsVO> resultDomain = new ResultDomain<>();
        
        try {
            if (userId == null || userId.isEmpty()) {
                resultDomain.fail("用户ID不能为空");
                return resultDomain;
            }

            if (startTime == null || endTime == null) {
                resultDomain.fail("开始时间和结束时间不能为空");
                return resultDomain;
            }

            // 统计总体数据
            Map<String, Object> statistics = learningHistoryMapper.selectLearningStatisticsByTimeRange(userId, startTime, endTime);
            
            // 获取学习的资源列表
            List<Map<String, Object>> learnedResources = learningHistoryMapper.selectLearnedResourcesByTimeRange(userId, startTime, endTime);

            // 构建VO
            LearningStatisticsVO statisticsVO = new LearningStatisticsVO();
            statisticsVO.setUserID(userId);
            
            if (statistics != null) {
                statisticsVO.setTotalDuration(getIntValue(statistics, "totalDuration"));
                statisticsVO.setLearnCount(getIntValue(statistics, "learnCount"));
                statisticsVO.setLearnDays(getIntValue(statistics, "learnDays"));
                statisticsVO.setResourceCount(getIntValue(statistics, "resourceCount"));
                statisticsVO.setCourseCount(getIntValue(statistics, "courseCount"));
                
                // 格式化时长
                statisticsVO.setTotalDurationFormatted(formatDurationString(statisticsVO.getTotalDuration()));
                
                // 计算平均每天学习时长
                if (statisticsVO.getLearnDays() > 0) {
                    statisticsVO.setAvgDailyDuration(statisticsVO.getTotalDuration() / statisticsVO.getLearnDays());
                }
            }

            resultDomain.success("查询学习统计成功", statisticsVO);

        } catch (Exception e) {
            logger.error("查询学习统计异常", e);
            resultDomain.fail("查询学习统计异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<LearningStatisticsVO> getUserLearningStatisticsByPeriod(String userId, String periodType) {
        ResultDomain<LearningStatisticsVO> resultDomain = new ResultDomain<>();
        
        try {
            if (userId == null || userId.isEmpty()) {
                resultDomain.fail("用户ID不能为空");
                return resultDomain;
            }

            // 计算时间范围
            Date endTime = new Date();
            Date startTime = calculateStartTime(endTime, periodType);

            if (startTime == null) {
                resultDomain.fail("无效的周期类型");
                return resultDomain;
            }

            ResultDomain<LearningStatisticsVO> statistics = getUserLearningStatistics(userId, startTime, endTime);
            if (statistics.isSuccess() && statistics.getData() != null) {
                statistics.getData().setPeriod(periodType);
            }

            return statistics;

        } catch (Exception e) {
            logger.error("查询学习统计异常", e);
            resultDomain.fail("查询学习统计异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<LearningHistoryVO> getCurrentUserLearningHistories(TbLearningHistory filter) {
        ResultDomain<LearningHistoryVO> resultDomain = new ResultDomain<>();
        
        try {
            TbSysUser currentUser = LoginUtil.getCurrentUser();
            if (currentUser == null) {
                resultDomain.fail("用户未登录");
                return resultDomain;
            }

            if (filter == null) {
                filter = new TbLearningHistory();
            }
            filter.setUserID(currentUser.getID());
            return getLearningHistories(filter);

        } catch (Exception e) {
            logger.error("查询当前用户学习历史异常", e);
            resultDomain.fail("查询当前用户学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<LearningStatisticsVO> getCurrentUserLearningStatistics(String periodType) {
        ResultDomain<LearningStatisticsVO> resultDomain = new ResultDomain<>();
        
        try {
            TbSysUser currentUser = LoginUtil.getCurrentUser();
            if (currentUser == null) {
                resultDomain.fail("用户未登录");
                return resultDomain;
            }

            return getUserLearningStatisticsByPeriod(currentUser.getID(), periodType);

        } catch (Exception e) {
            logger.error("查询当前用户学习统计异常", e);
            resultDomain.fail("查询当前用户学习统计异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    @Transactional
    public ResultDomain<Boolean> deleteLearningHistory(String id) {
        ResultDomain<Boolean> resultDomain = new ResultDomain<>();
        
        try {
            if (id == null || id.isEmpty()) {
                resultDomain.fail("历史记录ID不能为空");
                return resultDomain;
            }

            int result = learningHistoryMapper.deleteLearningHistory(id);
            if (result > 0) {
                resultDomain.success("删除学习历史成功", true);
            } else {
                resultDomain.fail("删除学习历史失败");
            }

        } catch (Exception e) {
            logger.error("删除学习历史异常", e);
            resultDomain.fail("删除学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    @Transactional
    public ResultDomain<Boolean> batchDeleteLearningHistories(List<String> ids) {
        ResultDomain<Boolean> resultDomain = new ResultDomain<>();
        
        try {
            if (ids == null || ids.isEmpty()) {
                resultDomain.fail("历史记录ID列表不能为空");
                return resultDomain;
            }

            int result = learningHistoryMapper.batchDeleteLearningHistories(ids);
            if (result > 0) {
                resultDomain.success("批量删除学习历史成功", true);
            } else {
                resultDomain.fail("批量删除学习历史失败");
            }

        } catch (Exception e) {
            logger.error("批量删除学习历史异常", e);
            resultDomain.fail("批量删除学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<LearningHistoryVO> getRecentLearningHistories(String userId, Integer limit) {
        ResultDomain<LearningHistoryVO> resultDomain = new ResultDomain<>();
        
        try {
            if (userId == null || userId.isEmpty()) {
                resultDomain.fail("用户ID不能为空");
                return resultDomain;
            }

            if (limit == null || limit <= 0) {
                limit = 10;
            }

            List<TbLearningHistory> historyList = learningHistoryMapper.selectRecentByUserId(userId, limit);
            List<LearningHistoryVO> historyVOList = historyList.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
            
            formatDuration(historyVOList);
            
            resultDomain.success("查询最近学习历史成功", historyVOList);

        } catch (Exception e) {
            logger.error("查询最近学习历史异常", e);
            resultDomain.fail("查询最近学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<TbLearningHistory> recordResourceView(String userId, String resourceId, Integer duration) {
        ResultDomain<TbLearningHistory> resultDomain = new ResultDomain<>();
        
        try {
            TbLearningHistory learningHistory = new TbLearningHistory();
            learningHistory.setUserID(userId);
            learningHistory.setResourceType(1); // 1=资源/新闻
            learningHistory.setResourceID(resourceId);
            learningHistory.setDuration(duration);
            learningHistory.setStartTime(new Date());
            
            return recordLearningHistory(learningHistory);

        } catch (Exception e) {
            logger.error("记录资源观看历史异常", e);
            resultDomain.fail("记录资源观看历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    @Override
    public ResultDomain<TbLearningHistory> recordCourseLearn(String userId, String courseId, String chapterId, String nodeId, Integer duration) {
        ResultDomain<TbLearningHistory> resultDomain = new ResultDomain<>();
        
        try {
            TbLearningHistory learningHistory = new TbLearningHistory();
            learningHistory.setUserID(userId);
            
            // 根据提供的信息确定资源类型
            if (nodeId != null && !nodeId.isEmpty()) {
                learningHistory.setResourceType(4); // 4=节点
                learningHistory.setNodeID(nodeId);
            } else if (chapterId != null && !chapterId.isEmpty()) {
                learningHistory.setResourceType(3); // 3=章节
                learningHistory.setChapterID(chapterId);
            } else {
                learningHistory.setResourceType(2); // 2=课程
            }
            
            learningHistory.setCourseID(courseId);
            learningHistory.setChapterID(chapterId);
            learningHistory.setNodeID(nodeId);
            learningHistory.setDuration(duration);
            learningHistory.setStartTime(new Date());
            
            return recordLearningHistory(learningHistory);

        } catch (Exception e) {
            logger.error("记录课程学习历史异常", e);
            resultDomain.fail("记录课程学习历史异常: " + e.getMessage());
        }

        return resultDomain;
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 发布学习时长更新事件
     */
    private void publishLearningTimeEvent(TbLearningHistory learningHistory) {
        try {
            // 构建成就事件
            AchievementEvent event = AchievementEvent.builder(
                learningHistory.getUserID(), 
                AchievementEventType.LEARNING_TIME_UPDATED
            )
            .value(learningHistory.getDuration()) // 学习时长（秒）
            .extra("resourceType", learningHistory.getResourceType())
            .extra("resourceID", learningHistory.getResourceID())
            .extra("courseID", learningHistory.getCourseID())
            .extra("historyID", learningHistory.getHistoryID())
            .build();
            
            // 发布事件（异步处理）
            eventPublisher.publishEvent(event);
            
            logger.debug("发布学习时长更新事件，用户ID: {}, 时长: {}秒", 
                learningHistory.getUserID(), learningHistory.getDuration());
        } catch (Exception e) {
            // 成就事件发布失败不应该影响主业务
            logger.error("发布学习时长事件失败", e);
        }
    }

    /**
     * 转换实体为VO
     */
    private LearningHistoryVO convertToVO(TbLearningHistory entity) {
        LearningHistoryVO vo = new LearningHistoryVO();
        BeanUtils.copyProperties(entity, vo);
        
        // 设置资源类型名称
        if (entity.getResourceType() != null) {
            vo.setResourceTypeName(getResourceTypeName(entity.getResourceType()));
        }
        
        return vo;
    }

    /**
     * 格式化时长列表
     */
    private void formatDuration(List<LearningHistoryVO> historyVOList) {
        if (historyVOList != null) {
            for (LearningHistoryVO vo : historyVOList) {
                if (vo.getDuration() != null) {
                    vo.setDurationFormatted(formatDurationString(vo.getDuration()));
                }
            }
        }
    }

    /**
     * 格式化时长（秒转为可读字符串）
     */
    private String formatDurationString(Integer seconds) {
        if (seconds == null || seconds == 0) {
            return "0秒";
        }

        int hours = seconds / 3600;
        int minutes = (seconds % 3600) / 60;
        int secs = seconds % 60;

        StringBuilder sb = new StringBuilder();
        if (hours > 0) {
            sb.append(hours).append("小时");
        }
        if (minutes > 0) {
            sb.append(minutes).append("分钟");
        }
        if (secs > 0 || sb.length() == 0) {
            sb.append(secs).append("秒");
        }

        return sb.toString();
    }

    /**
     * 获取资源类型名称
     */
    private String getResourceTypeName(Integer resourceType) {
        switch (resourceType) {
            case 1:
                return "资源/新闻";
            case 2:
                return "课程";
            case 3:
                return "章节";
            case 4:
                return "节点";
            default:
                return "未知";
        }
    }

    /**
     * 计算开始时间
     */
    private Date calculateStartTime(Date endTime, String periodType) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(endTime);

        if ("day".equalsIgnoreCase(periodType)) {
            calendar.add(Calendar.DAY_OF_MONTH, -1);
        } else if ("week".equalsIgnoreCase(periodType)) {
            calendar.add(Calendar.WEEK_OF_YEAR, -1);
        } else if ("month".equalsIgnoreCase(periodType)) {
            calendar.add(Calendar.MONTH, -1);
        } else {
            return null;
        }

        return calendar.getTime();
    }

    /**
     * 从Map中获取Integer值
     */
    private Integer getIntValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return 0;
        }
        if (value instanceof Integer) {
            return (Integer) value;
        }
        if (value instanceof Long) {
            return ((Long) value).intValue();
        }
        if (value instanceof BigDecimal) {
            return ((BigDecimal) value).intValue();
        }
        return 0;
    }
}

