package com.fs.course.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fs.common.core.domain.R;
import com.fs.common.exception.ServiceException;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.StringUtils;
import com.fs.course.config.CourseConfig;
import com.fs.course.domain.*;
import com.fs.course.dto.FsCourseQuestionBankImportDTO;
import com.fs.course.mapper.*;
import com.fs.course.param.FsCourseQuestionAnswerUParam;
import com.fs.course.service.IFsCourseQuestionBankService;
import com.fs.his.domain.FsUser;
import com.fs.his.mapper.FsUserMapper;
import com.fs.his.service.IFsStorePaymentService;
import com.fs.system.service.ISysConfigService;
import lombok.Getter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 题库Service业务层处理
 *
 * @author fs
 * @date 2024-09-07
 */
@Service
public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankService
{
    private static final Logger logger = LoggerFactory.getLogger(FsCourseQuestionBankServiceImpl.class);

    @Autowired
    private FsCourseQuestionBankMapper fsCourseQuestionBankMapper;
    @Autowired
    private FsUserMapper fsUserMapper;
    @Autowired
    private IFsStorePaymentService paymentService;
    @Autowired
    private FsCourseAnswerLogsMapper courseAnswerLogsMapper;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private FsCourseRedPacketLogMapper redPacketLogMapper;
    @Autowired
    private FsUserCourseVideoRedPackageMapper fsUserCourseVideoRedPackageMapper;
    @Autowired
    private FsUserCourseVideoMapper courseVideoMapper;
    @Autowired
    private FsCourseWatchLogMapper courseWatchLogMapper;
    @Autowired
    private FsUserCourseCategoryMapper courseCategoryMapper;
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 查询题库
     *
     * @param id 题库主键
     * @return 题库
     */
    @Override
    public FsCourseQuestionBank selectFsCourseQuestionBankById(Long id)
    {
        return fsCourseQuestionBankMapper.selectFsCourseQuestionBankById(id);
    }

    /**
     * 查询题库列表
     *
     * @param fsCourseQuestionBank 题库
     * @return 题库
     */
    @Override
    public List<FsCourseQuestionBank> selectFsCourseQuestionBankList(FsCourseQuestionBank fsCourseQuestionBank)
    {
        return fsCourseQuestionBankMapper.selectFsCourseQuestionBankList(fsCourseQuestionBank);
    }

    /**
     * 新增题库
     *
     * @param fsCourseQuestionBank 题库
     * @return 结果
     */
    @Override
    public int insertFsCourseQuestionBank(FsCourseQuestionBank fsCourseQuestionBank)
    {
        fsCourseQuestionBank.setCreateTime(DateUtils.getNowDate());
        return fsCourseQuestionBankMapper.insertFsCourseQuestionBank(fsCourseQuestionBank);
    }

    /**
     * 修改题库
     *
     * @param fsCourseQuestionBank 题库
     * @return 结果
     */
    @Override
    public int updateFsCourseQuestionBank(FsCourseQuestionBank fsCourseQuestionBank)
    {
        return fsCourseQuestionBankMapper.updateFsCourseQuestionBank(fsCourseQuestionBank);
    }

    /**
     * 批量删除题库
     *
     * @param ids 需要删除的题库主键
     * @return 结果
     */
    @Override
    public int deleteFsCourseQuestionBankByIds(Long[] ids)
    {
        return fsCourseQuestionBankMapper.deleteFsCourseQuestionBankByIds(ids);
    }

    /**
     * 删除题库信息
     *
     * @param id 题库主键
     * @return 结果
     */
    @Override
    public int deleteFsCourseQuestionBankById(Long id)
    {
        return fsCourseQuestionBankMapper.deleteFsCourseQuestionBankById(id);
    }

    @Override
    public R courseAnswerByFsUser(FsCourseQuestionAnswerUParam param) {
        FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
        if (user==null){
            return R.error("未识别到领取信息");
        }
        //获取配置参数
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);

        //本次答题正确个数
        int thisRightCount = 0;
        //用户答错次数
        int errorCount = 0;
        List<FsCourseQuestionBank> incorrectQuestions = new ArrayList<>();
        //日志id
        Long logId = null;

        new FsCourseAnswerLogs();
        FsCourseAnswerLogs rightLog;
        //判断短链类型

        FsCourseWatchLog log = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getUserId(), param.getCompanyUserId());
        if (log==null){
            return R.error("无记录");
        }
        if (log.getLogType()!=2){
            return R.error("未完课");
        }
        logId = log.getLogId();

        rightLog = courseAnswerLogsMapper.selectRightLogByCourseVideo(param.getVideoId(), param.getUserId(), param.getQwUserId());
        if (rightLog != null) {
            if (log.getRewardType() != null) {
                // 增加判断，去查询红包记录是否已发送成功，如果成功，则返回当前提示，否则返回答题成功（让其可以继续答题，直到红包领取完成）
                FsCourseRedPacketLog fsCourseRedPacketLog = redPacketLogMapper.selectUserFsCourseRedPacketLog(param.getVideoId(), param.getUserId(),param.getPeriodId());
                if(fsCourseRedPacketLog != null && fsCourseRedPacketLog.getStatus() == 1) {
                    return R.error("该课程已答题完成，不可重复答题");
                } else {
                    return R.ok("答题成功");
                }
            } else {
                return R.ok("答题成功");
            }
        }
        errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),param.getQwUserId(),log.getProject());



        if (errorCount >= config.getAnswerErrorCount()) {
            return R.error("该课题到达答错次数限制");
        }
        int remainCount = config.getAnswerErrorCount()-errorCount-1;

        // 一次性获取所有问题的正确答案
        List<FsCourseQuestionBank> questions = param.getQuestions();
        if (questions != null && !questions.isEmpty()) {
            Map<Long, FsCourseQuestionBank> correctAnswersMap = fsCourseQuestionBankMapper.selectFsCourseQuestionBankByIds(
                    questions.stream().map(FsCourseQuestionBank::getId).collect(Collectors.toList())
            ).stream().collect(Collectors.toMap(FsCourseQuestionBank::getId, question -> question));

            for (FsCourseQuestionBank questionBank : questions) {
                FsCourseQuestionBank correctAnswer = correctAnswersMap.get(questionBank.getId());
                if (correctAnswer.getType() == 1) {
                    if (questionBank.getAnswer().equals(correctAnswer.getAnswer())) {
                        thisRightCount++;
                    } else {
                        correctAnswer.setAnswer(null);
                        incorrectQuestions.add(correctAnswer);
                    }
                } else if (correctAnswer.getType() == 2) {
                    String[] userAnswers = convertStringToArray(questionBank.getAnswer());
                    String[] correctAnswers = convertStringToArray(correctAnswer.getAnswer());

                    Arrays.sort(userAnswers);
                    Arrays.sort(correctAnswers);

                    if (Arrays.equals(userAnswers, correctAnswers)) {
                        thisRightCount++;
                    } else {
                        correctAnswer.setAnswer(null);
                        incorrectQuestions.add(correctAnswer);
                    }
                }
            }
        }
        FsCourseAnswerLogs logs = new FsCourseAnswerLogs();
        logs.setWatchLogId(logId);
        logs.setUserId(param.getUserId());
        logs.setVideoId(param.getVideoId());
        logs.setCourseId(param.getCourseId());
        logs.setCompanyId(param.getCompanyId());
        logs.setCompanyUserId(param.getCompanyUserId());
        logs.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null );
        logs.setQuestionJson(JSONObject.toJSONString(questions));
        logs.setCreateTime(new Date());
        logs.setPeriodId(param.getPeriodId());

        if (thisRightCount == questions.size()) {
            logs.setIsRight(1);
            //  使用分布式锁保护答题记录插入
            return insertAnswerLogWithLock(logs, param, "答题成功", null);
        } else {
            logs.setIsRight(0);
            //  使用分布式锁保护答题记录插入
            return insertAnswerLogWithLock(logs, param, "答题失败",
                R.ok().put("incorrectQuestions", incorrectQuestions).put("remain", remainCount));
        }
    }

    @Override
    @Transactional
    public R courseAnswerIsOpen(FsCourseQuestionAnswerUParam param, boolean isH5User) {
        //获取配置参数
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);

        //本次答题正确个数
        int thisRightCount = 0;
        //用户答错次数
        int errorCount = 0;
        List<FsCourseQuestionBank> incorrectQuestions = new ArrayList<>();
        //日志id
        Long logId = null;

        FsCourseAnswerLogs rightLog = new FsCourseAnswerLogs();
        //判断短链类型
        if (param.getLinkType()!=null&&param.getLinkType()==1){
            rightLog = courseAnswerLogsMapper.selectRightLogByCourseVideo(param.getVideoId(), param.getUserId(),null);
            if (rightLog!=null){
                return R.error("该课程已答题完成，不可重复答题");
            }
            errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),null, null);

        }else {
            FsCourseWatchLog log;
            if(isH5User){
                log = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getUserId(), param.getCompanyUserId());
            } else {
                log = courseWatchLogMapper.getWatchCourseVideoIsOpen(param.getUserId(), param.getVideoId());
            }
            if (log==null){
                return R.error("无记录");
            }
            if (log.getLogType()!=2){
                return R.error("未完课");
            }
            logId = log.getLogId();

            rightLog = courseAnswerLogsMapper.selectRightLogByCourseVideoIsOpen(param.getVideoId(), param.getUserId());
            if (rightLog != null) {
                return R.ok("答题成功");
            }
            errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),param.getQwUserId(), log.getProject());
        }


        if (errorCount >= config.getAnswerErrorCount()) {
            return R.error("该课题到达答错次数限制");
        }
        int remainCount = config.getAnswerErrorCount()-errorCount-1;

        // 一次性获取所有问题的正确答案
        Map<Long, FsCourseQuestionBank> correctAnswersMap = fsCourseQuestionBankMapper.selectFsCourseQuestionBankByIds(
                param.getQuestions().stream().map(FsCourseQuestionBank::getId).collect(Collectors.toList())
        ).stream().collect(Collectors.toMap(FsCourseQuestionBank::getId, question -> question));

        for (FsCourseQuestionBank questionBank : param.getQuestions()) {
            FsCourseQuestionBank correctAnswer = correctAnswersMap.get(questionBank.getId());
            if (correctAnswer.getType() == 1) {
                if (questionBank.getAnswer().equals(correctAnswer.getAnswer())) {
                    thisRightCount++;
                } else {
                    correctAnswer.setAnswer(null);
                    incorrectQuestions.add(correctAnswer);
                }
            } else if (correctAnswer.getType() == 2) {
                String[] userAnswers = convertStringToArray(questionBank.getAnswer());
                String[] correctAnswers = convertStringToArray(correctAnswer.getAnswer());

                Arrays.sort(userAnswers);
                Arrays.sort(correctAnswers);

                if (Arrays.equals(userAnswers, correctAnswers)) {
                    thisRightCount++;
                } else {
                    correctAnswer.setAnswer(null);
                    incorrectQuestions.add(correctAnswer);
                }
            }
        }

        FsCourseAnswerLogs logs = new FsCourseAnswerLogs();
        logs.setWatchLogId(logId);
        logs.setUserId(param.getUserId());
        logs.setVideoId(param.getVideoId());
        logs.setCourseId(param.getCourseId());
        /*logs.setCompanyId(param.getCompanyId());
        logs.setCompanyUserId(param.getCompanyUserId());
        logs.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null );*/
        logs.setQuestionJson(JSONObject.toJSONString(param.getQuestions()));
        logs.setCreateTime(new Date());
        logs.setPeriodId(param.getPeriodId());

        if (thisRightCount == param.getQuestions().size()) {
            logs.setIsRight(1);
            //  使用分布式锁保护答题记录插入
            return insertAnswerLogWithLock(logs, param, "答题成功", null);
        } else {
            logs.setIsRight(0);
            //  使用分布式锁保护答题记录插入
            return insertAnswerLogWithLock(logs, param, "答题失败",
                R.ok().put("incorrectQuestions", incorrectQuestions).put("remain", remainCount));
        }
    }

    @Override
    @Transactional
    public R courseAnswer(FsCourseQuestionAnswerUParam param,Boolean isH5User) {
        //获取配置参数
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);

        //本次答题正确个数
        int thisRightCount = 0;
        //用户答错次数
        int errorCount = 0;
        List<FsCourseQuestionBank> incorrectQuestions = new ArrayList<>();
        //日志id
        Long logId = null;

        FsCourseAnswerLogs rightLog = new FsCourseAnswerLogs();
        //判断短链类型
        if (param.getLinkType()!=null&&param.getLinkType()==1){
            rightLog = courseAnswerLogsMapper.selectRightLogByCourseVideo(param.getVideoId(), param.getUserId(),null);
            if (rightLog!=null){
                return R.error("该课程已答题完成，不可重复答题");
            }
            errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),null, null);

        }else {
            FsCourseWatchLog log;
            if(isH5User){
                log = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getUserId(), param.getCompanyUserId());
            } else {
                log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
            }
            if (log==null){
                return R.error("无记录");
            }
            if (log.getLogType()!=2){
                return R.error("未完课");
            }
            logId = log.getLogId();

            rightLog = courseAnswerLogsMapper.selectRightLogByCourseVideo(param.getVideoId(), param.getUserId(), param.getQwUserId());
            if (rightLog != null) {
                if (log.getRewardType() != null) {
                    // 增加判断，去查询红包记录是否已发送成功，如果成功，则返回当前提示，否则返回答题成功（让其可以继续答题，直到红包领取完成）
                    FsCourseRedPacketLog fsCourseRedPacketLog = redPacketLogMapper.selectUserFsCourseRedPacketLog(param.getVideoId(), param.getUserId(),param.getPeriodId());
                    if(fsCourseRedPacketLog != null && fsCourseRedPacketLog.getStatus() == 1) {
                        return R.error("该课程已答题完成，不可重复答题");
                    } else {
                        return R.ok("答题成功");
                    }
                } else {
                    return R.ok("答题成功");
                }
            }
            errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),param.getQwUserId(), log.getProject());
        }


        if (errorCount >= config.getAnswerErrorCount()) {
            return R.error("该课题到达答错次数限制");
        }
        int remainCount = config.getAnswerErrorCount()-errorCount-1;

        // 一次性获取所有问题的正确答案
        Map<Long, FsCourseQuestionBank> correctAnswersMap = fsCourseQuestionBankMapper.selectFsCourseQuestionBankByIds(
                param.getQuestions().stream().map(FsCourseQuestionBank::getId).collect(Collectors.toList())
        ).stream().collect(Collectors.toMap(FsCourseQuestionBank::getId, question -> question));

        for (FsCourseQuestionBank questionBank : param.getQuestions()) {
            FsCourseQuestionBank correctAnswer = correctAnswersMap.get(questionBank.getId());
            if (correctAnswer.getType() == 1) {
                if (questionBank.getAnswer().equals(correctAnswer.getAnswer())) {
                    thisRightCount++;
                } else {
                    correctAnswer.setAnswer(null);
                    incorrectQuestions.add(correctAnswer);
                }
            } else if (correctAnswer.getType() == 2) {
                String[] userAnswers = convertStringToArray(questionBank.getAnswer());
                String[] correctAnswers = convertStringToArray(correctAnswer.getAnswer());

                Arrays.sort(userAnswers);
                Arrays.sort(correctAnswers);

                if (Arrays.equals(userAnswers, correctAnswers)) {
                    thisRightCount++;
                } else {
                    correctAnswer.setAnswer(null);
                    incorrectQuestions.add(correctAnswer);
                }
            }
        }

        FsCourseAnswerLogs logs = new FsCourseAnswerLogs();
        logs.setWatchLogId(logId);
        logs.setUserId(param.getUserId());
        logs.setVideoId(param.getVideoId());
        logs.setCourseId(param.getCourseId());
        logs.setCompanyId(param.getCompanyId());
        logs.setCompanyUserId(param.getCompanyUserId());
        logs.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null );
        logs.setQuestionJson(JSONObject.toJSONString(param.getQuestions()));
        logs.setCreateTime(new Date());
        logs.setPeriodId(param.getPeriodId());

        if (thisRightCount == param.getQuestions().size()) {
            logs.setIsRight(1);
            //  使用分布式锁保护答题记录插入
            return insertAnswerLogWithLock(logs, param, "答题成功", null);
        } else {
            logs.setIsRight(0);
            //  使用分布式锁保护答题记录插入
            return insertAnswerLogWithLock(logs, param, "答题失败",
                R.ok().put("incorrectQuestions", incorrectQuestions).put("remain", remainCount));
        }
    }

    /**
     * 题目导入
     *
     * @param list     数据
     * @param nickName 昵称
     * @param userId   用户ID
     * @return String
     */

    @Override
    @Transactional
    public String importData(List<FsCourseQuestionBankImportDTO> list, String nickName, Long userId) {
        if (Objects.isNull(list) || list.isEmpty()) {
            throw new ServiceException("导入数据不能为空");
        }

        ImportResult result = new ImportResult();
        List<FsCourseQuestionBank> insertList = new ArrayList<>();
        List<FsCourseQuestionBank> updateList = new ArrayList<>();
        Map<String, FsUserCourseCategory> categoryData = courseCategoryMapper.queryAllCategoryData();

        for (FsCourseQuestionBankImportDTO importDTO : list) {
            try {
                // 数据验证
                ValidationResult validation = validateImportData(importDTO);
                if (!validation.isValid()) {
                    result.addFailure(importDTO.getTitle(), validation.getErrorMessage());
                    continue;
                }

                // 构建题目对象
                FsCourseQuestionBank questionBank = buildQuestionBank(importDTO, categoryData, nickName);
                questionBank.setUserId(userId);

                // 根据标题、题目类别、题目子类别查询是否存在
                FsCourseQuestionBank existingQuestion = fsCourseQuestionBankMapper.selectFsCourseQuestionBankByTitleAndType(
                        importDTO.getTitle(),
                        questionBank.getQuestionType(),
                        questionBank.getQuestionSubType()
                );

                if (existingQuestion != null) {
                    // 相同标题且相同类别，更新除标题外的其他信息
                    questionBank.setId(existingQuestion.getId());
                    updateList.add(questionBank);
                    result.addUpdate(importDTO.getTitle());
                } else {
                    // 不同类别下的相同标题，或全新的标题，都新增
                    insertList.add(questionBank);
                    result.addInsert(importDTO.getTitle());
                }

            } catch (Exception e) {
                result.addFailure(importDTO.getTitle(), "导入异常: " + e.getMessage());
            }
        }

        // 批量新增
        if (!insertList.isEmpty()) {
            fsCourseQuestionBankMapper.insertFsCourseQuestionBankBatch(insertList);
        }

        // 批量更新
        if (!updateList.isEmpty()) {
            updateList.forEach(fsCourseQuestionBankMapper::updateFsCourseQuestionTitle);
//            fsCourseQuestionBankMapper.updateFsCourseQuestionBankBatch(updateList);
        }

        return result.buildResultMessage();
    }


    /**
     * 验证导入数据
     */
    private ValidationResult validateImportData(FsCourseQuestionBankImportDTO importDTO) {
        // 基础字段验证
        if (StringUtils.isBlank(importDTO.getTitle())) {
            return ValidationResult.fail("标题不能为空");
        }
        if (StringUtils.isBlank(importDTO.getType())) {
            return ValidationResult.fail("类别不能为空");
        }
        if (Objects.isNull(importDTO.getSort())) {
            return ValidationResult.fail("排序不能为空");
        }
        if (StringUtils.isBlank(importDTO.getAnswer())) {
            return ValidationResult.fail("答案不能为空");
        }

        // 选项验证
        ValidationResult optionValidation = validateOptions(importDTO);
        if (!optionValidation.isValid()) {
            return optionValidation;
        }

        // 题目类型验证
        if (!isValidQuestionType(importDTO.getType())) {
            return ValidationResult.fail("题目类型不正确，仅支持单选题和多选题");
        }

        // 答案验证
        return validateAnswers(importDTO);
    }

    /**
     * 验证选项 鹤颜堂项目允许两个答案
     */
    private ValidationResult validateOptions(FsCourseQuestionBankImportDTO importDTO) {
        if (StringUtils.isBlank(importDTO.getQuestionA()) ||
                StringUtils.isBlank(importDTO.getQuestionB())
                ) {
            return ValidationResult.fail("选项A、B不能为空");
        }
        return ValidationResult.success();
    }

    /**
     * 验证题目类型
     */
    private boolean isValidQuestionType(String type) {
        return type.contains("单") || type.contains("多");
    }

    /**
     * 验证答案
     */
    private ValidationResult validateAnswers(FsCourseQuestionBankImportDTO importDTO) {
        String[] answers = importDTO.getAnswer().trim().toUpperCase().split("");

        // 多选题答案数量验证
        if (importDTO.getType().contains("多") && answers.length < 2) {
            return ValidationResult.fail("多选题答案不能少于2个");
        }

        // 答案选项验证
        List<String> validOptions = getValidOptions(importDTO);
        for (String answer : answers) {
            if (!validOptions.contains(answer.trim())) {
                return ValidationResult.fail("答案不在选项中");
            }
        }

        return ValidationResult.success();
    }

    /**
     * 获取有效选项列表
     */
    private List<String> getValidOptions(FsCourseQuestionBankImportDTO importDTO) {
        List<String> options = new ArrayList<>(Arrays.asList("A", "B", "C"));
        if (StringUtils.isNotBlank(importDTO.getQuestionD())) {
            options.add("D");
        }
        return options;
    }

    /**
     * 构建题目对象
     */
    private FsCourseQuestionBank buildQuestionBank(FsCourseQuestionBankImportDTO importDTO,
                                                   Map<String, FsUserCourseCategory> categoryData,
                                                   String nickName) {
        FsCourseQuestionBank questionBank = new FsCourseQuestionBank();

        // 基础信息
        questionBank.setTitle(importDTO.getTitle());
        questionBank.setType(getQuestionTypeCode(importDTO.getType()));
        questionBank.setSort(importDTO.getSort());
        questionBank.setStatus(parseStatus(importDTO.getStatus()));
        questionBank.setCreateTime(new Date());
        questionBank.setCreateBy(nickName);

        // 分类信息
        setQuestionCategories(questionBank, importDTO, categoryData);

        // 选项和答案
        questionBank.setQuestion(buildQuestionOptions(importDTO));
        questionBank.setAnswer(buildAnswer(importDTO));

        return questionBank;
    }

    /**
     * 获取题目类型编码
     */
    private Long getQuestionTypeCode(String type) {
        return type.contains("单") ? 1L : 2L;
    }

    /**
     * 解析状态
     */
    private Long parseStatus(String statusStr) {
        if (StringUtils.isBlank(statusStr)) {
            return 1L;
        }
        try {
            return statusStr.contains("正常") ? 1L : 0L;
        } catch (Exception e) {
            return 1L;
        }
    }

    /**
     * 设置题目分类
     */
    private void setQuestionCategories(FsCourseQuestionBank questionBank,
                                       FsCourseQuestionBankImportDTO importDTO,
                                       Map<String, FsUserCourseCategory> categoryData) {
        if (StringUtils.isBlank(importDTO.getQuestionType())) {
            return;
        }

        FsUserCourseCategory category = categoryData.get(importDTO.getQuestionType().trim()+"-0");
        if (category != null) {
            questionBank.setQuestionType(category.getCateId());

            // 子分类
            if (StringUtils.isNotBlank(importDTO.getQuestionSubTyp())) {
                FsUserCourseCategory subCategory = categoryData.get(importDTO.getQuestionSubTyp().trim()+"-" + category.getCateId());
                if (subCategory != null) {
                    questionBank.setQuestionSubType(subCategory.getCateId());
                }
            }
        }
    }

    /**
     * 构建选项JSON
     */
    private String buildQuestionOptions(FsCourseQuestionBankImportDTO importDTO) {
        JSONArray questionArray = new JSONArray();
        String[] answers = importDTO.getAnswer().trim().toUpperCase().split("");
        List<String> answerList = Arrays.asList(answers);

        // 构建选项
        addOption(questionArray, importDTO.getQuestionA(), answerList.contains("A"), 0);
        addOption(questionArray, importDTO.getQuestionB(), answerList.contains("B"), 1);
        if (StringUtils.isNotBlank(importDTO.getQuestionC())) {
            addOption(questionArray, importDTO.getQuestionC(), answerList.contains("C"), 2);
        }

        if (StringUtils.isNotBlank(importDTO.getQuestionD())) {
            addOption(questionArray, importDTO.getQuestionD(), answerList.contains("D"), 3);
        }

        return JSON.toJSONString(questionArray);
    }

    /**
     * 添加选项
     */
    private void addOption(JSONArray questionArray, String optionText,
                           boolean isAnswer, int indexId) {
        JSONObject option = new JSONObject();
        option.put("name", optionText.trim());
        option.put("isAnswer", isAnswer ? 1 : 0);
        option.put("indexId", indexId);
        questionArray.add(option);
    }

    /**
     * 构建答案
     */
    private String buildAnswer(FsCourseQuestionBankImportDTO importDTO) {
        String[] answers = importDTO.getAnswer().trim().toUpperCase().split("");
        List<String> answerList = Arrays.asList(answers);

        Map<String, String> questionMap = new HashMap<>();
        questionMap.put("A", importDTO.getQuestionA().trim());
        questionMap.put("B", importDTO.getQuestionB().trim());
        if(StringUtils.isNotBlank(importDTO.getQuestionC())){
            questionMap.put("C", importDTO.getQuestionC().trim());
        }
        if(StringUtils.isNotBlank(importDTO.getQuestionD())){
            questionMap.put("D", importDTO.getQuestionD().trim());
        }

        List<String> selectedAnswers = answerList.stream()
                .map(questionMap::get)
                .collect(Collectors.toList());

        if (answerList.size() == 1) {
            return selectedAnswers.get(0);
        }

        return JSON.toJSONString(selectedAnswers);
    }

    // 辅助类
    @Getter
    private static class ValidationResult {
        private final boolean valid;
        private final String errorMessage;

        private ValidationResult(boolean valid, String errorMessage) {
            this.valid = valid;
            this.errorMessage = errorMessage;
        }

        public static ValidationResult success() {
            return new ValidationResult(true, null);
        }

        public static ValidationResult fail(String message) {
            return new ValidationResult(false, message);
        }

    }

    private static class ImportResult {
        private int insertNum = 0;
        private int updateNum = 0;
        private int failureNum = 0;
        private final StringBuilder insertMsg = new StringBuilder();
        private final StringBuilder updateMsg = new StringBuilder();
        private final StringBuilder errorMsg = new StringBuilder();

        public void addInsert(String title) {
            insertNum++;
            insertMsg.append("<br/>").append(insertNum).append("、题目 ").append(title).append(" 新增成功");
        }

        public void addUpdate(String title) {
            updateNum++;
            updateMsg.append("<br/>").append(updateNum).append("、题目 ").append(title).append(" 更新成功");
        }

        public void addFailure(String title, String error) {
            failureNum++;
            errorMsg.append("<br/>").append(failureNum).append("、题目 ").append(title).append(" 导入失败：").append(error);
        }

        public String buildResultMessage() {
            int totalSuccess = insertNum + updateNum;
            StringBuilder message = new StringBuilder();
            message.append("导入完成！成功").append(totalSuccess).append(" 条");
            message.append("（新增").append(insertNum).append("条，更新").append(updateNum).append("条）");
            message.append("，失败").append(failureNum).append("条。");
            message.append(errorMsg);
            message.append(insertMsg);
            message.append(updateMsg);
            return message.toString();
        }
    }

    /**
     * 根据ID查询题目
     * @param ids   ids
     * @return  list
     */
    @Override
    public List<FsCourseQuestionBank> selectFsCourseQuestionBankByIds(List<Long> ids) {
        return fsCourseQuestionBankMapper.selectFsCourseQuestionBankByIds(ids);
    }

    /**
     * 题目导出
     * @param fsCourseQuestionBank  参数
     * @return  list
     */
    @Override
    public List<FsCourseQuestionBankImportDTO> exportData(FsCourseQuestionBank fsCourseQuestionBank) {
        List<FsCourseQuestionBank> fsCourseQuestionBanks = fsCourseQuestionBankMapper.selectFsCourseQuestionBankList(fsCourseQuestionBank);
        Map<Long, FsUserCourseCategory> categoryMap = courseCategoryMapper.queryAllIdKeyCategoryData();

        // 辅助方法：根据ID从Map获取分类名称
        Function<Long, String> getCategoryName = id -> Optional.ofNullable(categoryMap.get(id))
                .map(FsUserCourseCategory::getCateName)
                .orElse(null);

        Map<Integer, BiConsumer<FsCourseQuestionBankImportDTO, String>> questionSetters = new HashMap<>();
        questionSetters.put(0, FsCourseQuestionBankImportDTO::setQuestionA);
        questionSetters.put(1, FsCourseQuestionBankImportDTO::setQuestionB);
        questionSetters.put(2, FsCourseQuestionBankImportDTO::setQuestionC);
        questionSetters.put(3, FsCourseQuestionBankImportDTO::setQuestionD);

        Map<Integer, String> answerLettersMap = new HashMap<>();
        answerLettersMap.put(0, "A");
        answerLettersMap.put(1, "B");
        answerLettersMap.put(2, "C");
        answerLettersMap.put(3, "D");

        return fsCourseQuestionBanks.stream().map(q -> {
            FsCourseQuestionBankImportDTO dto = new FsCourseQuestionBankImportDTO();
            dto.setTitle(q.getTitle());
            dto.setSort(q.getSort());
            dto.setType(q.getType() == 1 ? "单选" : "多选");
            Optional.ofNullable(q.getQuestionType()).map(getCategoryName).ifPresent(dto::setQuestionType);
            Optional.ofNullable(q.getQuestionSubType()).map(getCategoryName).ifPresent(dto::setQuestionSubTyp);
            dto.setStatus(q.getStatus() == 1 ? "正常" : "停用");

            StringBuilder answersBuilder = new StringBuilder();
            JSONArray array = JSON.parseArray(q.getQuestion());
            array.forEach(jsonObject -> {
                JSONObject json = (JSONObject) jsonObject;
                int index = json.getInteger("indexId");
                String name = json.getString("name");
                int isAnswer = json.getInteger("isAnswer");

                questionSetters.get(index).accept(dto, name);
                if (isAnswer == 1) {
                    answersBuilder.append(answerLettersMap.get(index));
                }

            });
            dto.setAnswer(answersBuilder .toString());
            return dto;
        }).collect(Collectors.toList());
    }


    public static String[] convertStringToArray(String inputString) {
        String cleanString = inputString.replaceAll("[\\[\\]\"\\s]", "");
        return cleanString.split(",");
    }

    /**
     * 使用分布式锁插入答题记录（防止重复答题）
     * @param logs 答题记录
     * @param param 答题参数
     * @param successMsg 成功消息
     * @param extraData 额外数据（用于答题失败时返回错误题目）
     * @return 结果
     */
    private R insertAnswerLogWithLock(FsCourseAnswerLogs logs, FsCourseQuestionAnswerUParam param,
                                       String successMsg, R extraData) {
        // 构建分布式锁key（基于业务键）
        String lockKey = String.format("answer:user:%s:video:%s:period:%s:right:%s",
            param.getUserId(), param.getVideoId(), param.getPeriodId(), logs.getIsRight());
        RLock lock = redissonClient.getLock(lockKey);

        try {
            //  尝试获取锁（等待3秒，持有10秒）
            boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (!locked) {
                logger.warn("【答题提交】获取锁失败，userId:{}, videoId:{}, periodId:{}",
                    param.getUserId(), param.getVideoId(), param.getPeriodId());
                return R.error("系统繁忙，请稍后重试！");
            }

            //  双重检查：再次查询是否已经答过题
            FsCourseAnswerLogs existQuery = new FsCourseAnswerLogs();
            existQuery.setUserId(param.getUserId());
            existQuery.setVideoId(param.getVideoId());
            existQuery.setPeriodId(param.getPeriodId());
            existQuery.setIsRight(logs.getIsRight());
            List<FsCourseAnswerLogs> existLogs =
                courseAnswerLogsMapper.selectFsCourseAnswerLogsList(existQuery);

            if (existLogs != null && !existLogs.isEmpty()) {
                logger.warn("【答题提交】用户已答过题，userId:{}, videoId:{}, periodId:{}, is_right:{}, 已存在{}条记录",
                    param.getUserId(), param.getVideoId(), param.getPeriodId(),
                    logs.getIsRight(), existLogs.size());

                // 如果是答对了，返回成功；如果是答错了，也返回之前的结果
                if (logs.getIsRight() == 1) {
                    return R.ok("该课程已答题完成，不可重复答题");
                } else {
                    return R.ok(successMsg);
                }
            }

            //  插入答题记录
            try {
                courseAnswerLogsMapper.insertFsCourseAnswerLogs(logs);
                logger.info("【答题提交】答题记录插入成功，userId:{}, videoId:{}, is_right:{}",
                    param.getUserId(), param.getVideoId(), logs.getIsRight());

                // 返回结果
                if (extraData != null) {
                    return R.ok(successMsg)
                        .put("incorrectQuestions", extraData.get("incorrectQuestions"))
                        .put("remain", extraData.get("remain"));
                } else {
                    return R.ok(successMsg);
                }
            } catch (DuplicateKeyException e) {
                //  捕获唯一索引冲突异常（数据库最后一道防线）
                logger.warn("【答题提交】唯一索引冲突，用户已答过题，userId:{}, videoId:{}, periodId:{}",
                    param.getUserId(), param.getVideoId(), param.getPeriodId());

                if (logs.getIsRight() == 1) {
                    return R.error("该课程已答题完成，不可重复答题");
                } else {
                    return R.ok(successMsg);
                }
            }

        } catch (InterruptedException e) {
            logger.error("【答题提交】获取锁被中断", e);
            Thread.currentThread().interrupt();
            return R.error("系统繁忙，请稍后重试！");
        } catch (Exception e) {
            logger.error("【答题提交】插入答题记录异常，userId:{}, videoId:{}",
                param.getUserId(), param.getVideoId(), e);
            return R.error("答题提交失败，请联系客服");
        } finally {
            //  释放锁
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
                logger.info("【答题提交】释放锁成功，userId:{}, videoId:{}",
                    param.getUserId(), param.getVideoId());
            }
        }
    }
}
