package com.fs.course.service.impl;

import cn.hutool.json.JSONUtil;
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.store.domain.FsUser;
import com.fs.store.mapper.FsUserMapper;
import com.fs.store.service.IFsStorePaymentService;
import com.fs.system.service.ISysConfigService;
import com.hc.openapi.tool.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.Size;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 题库Service业务层处理
 *
 * @author fs
 * @date 2024-09-07
 */
@Service
public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankService
{
    @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;

    /**
     * 查询题库
     *
     * @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
    @Transactional
    public R courseAnswer(FsCourseQuestionAnswerUParam param, Boolean isH5User) {
        FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
        if (StringUtils.isEmpty(user.getMpOpenId())){
            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;

        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);

        }else {
            FsCourseWatchLog log;
            if(isH5User){
               log = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getUserId());
            } 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) {
                    return R.error("该课程已答题完成，不可重复答题");
                } else {
                    return R.ok("答题成功");
                }
            }
            errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),param.getQwUserId());
        }


        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);
            courseAnswerLogsMapper.insertFsCourseAnswerLogs(logs);
            return R.ok("答题成功");
        } else {
            logs.setIsRight(0);
            courseAnswerLogsMapper.insertFsCourseAnswerLogs(logs);
            return R.ok("答题失败").put("incorrectQuestions", incorrectQuestions).put("remain",remainCount);
        }
    }


    @Override
    @Transactional
    public R courseAnswerByfsUser(FsCourseQuestionAnswerUParam param) {
        FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
        if (StringUtils.isEmpty(user.getMpOpenId())){
            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<>();

        //查询看课记录
        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByFsUser(param.getUserId(),param.getVideoId(),param.getCompanyUserId());

        if (log==null){
            return R.error("无记录");
        }
        if (log.getLogType()!=2){
            return R.error("未完课");
        }

        FsCourseAnswerLogs rightLog = courseAnswerLogsMapper.selectRightLogByCourseVideoByFsUser(log.getLogId());
        if (rightLog != null) {
            if (log.getRewardType() != null) {
                return R.error("该课程已答题完成，不可重复答题");
            } else {
                return R.ok("答题成功");
            }
        }
        errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),param.getQwUserId());


        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(log.getLogId());
        logs.setUserId(param.getUserId());
        logs.setVideoId(param.getVideoId());
        logs.setCourseId(param.getCourseId());
        logs.setCompanyId(param.getCompanyId());
        logs.setCompanyUserId(param.getCompanyUserId());
        logs.setQuestionJson(JSONObject.toJSONString(param.getQuestions()));
        logs.setCreateTime(new Date());

        if (thisRightCount == param.getQuestions().size()) {
            logs.setIsRight(1);
            courseAnswerLogsMapper.insertFsCourseAnswerLogs(logs);
            return R.ok("答题成功");
        } else {
            logs.setIsRight(0);
            courseAnswerLogsMapper.insertFsCourseAnswerLogs(logs);
            return R.ok("答题失败").put("incorrectQuestions", incorrectQuestions).put("remain",remainCount);
        }
    }

    /**
     * 题目导入
     *
     * @param list     数据
     * @param nickName 昵称
     * @return String
     */
    @Override
    public String importData(List<FsCourseQuestionBankImportDTO> list, @Size String nickName) {
        if (Objects.isNull(list) || list.isEmpty()) {
            throw new ServiceException("导入数据不能为空");
        }

        int successNum = 0;
        int failureNum = 0;
        StringBuilder importSuccessMsg = new StringBuilder();
        StringBuilder importErrorMsg = new StringBuilder();
        StringBuilder importMsg = new StringBuilder();

        for (FsCourseQuestionBankImportDTO importDTO : list) {
            try {
                String title = importDTO.getTitle();
                String type = importDTO.getType();
                String questionType = importDTO.getQuestionType();
                String question = importDTO.getQuestion();
                String answer = importDTO.getAnswer();

                if (StringUtils.isBlank(title) || StringUtils.isBlank(type) || StringUtils.isBlank(question) || StringUtils.isBlank(answer)) {
                    String msg = "<br/>" + failureNum + "、题目 " + title + " 导入失败：信息不完整";
                    importErrorMsg.append(msg);
                    failureNum++;
                    continue;
                }

                if (!type.contains("单") && !type.contains("多")) {
                    String msg = "<br/>" + failureNum + "、题目 " + title + " 导入失败：题目类型不正确";
                    importErrorMsg.append(msg);
                    failureNum++;
                    continue;
                }

                // 判断答案是否在选项里
                String[] questions = question.split("\\|");
                String[] answers = answer.split("\\|");

                if (type.contains("多") && answers.length < 2) {
                    String msg = "<br/>" + failureNum + "、题目 " + title + " 导入失败：多选题答案不能少于2个";
                    importErrorMsg.append(msg);
                    failureNum++;
                    continue;
                }

                List<String> optionsList = Arrays.asList(questions);
                boolean allAnswersInOptions = true;

                // 遍历每一个正确答案文本
                for (String correctAnswer : answers) {
                    // 检查当前正确答案文本是否存在于选项列表中
                    if (!optionsList.contains(correctAnswer.trim())) {
                        allAnswersInOptions = false; // 发现一个不在选项里的答案
                        break;
                    }
                }

                if (!allAnswersInOptions) {
                    String msg = "<br/>" + failureNum + "、题目 " + title + " 导入失败：答案不在选项中";
                    importErrorMsg.append(msg);
                    failureNum++;
                    continue;
                }

                JSONArray questionArray = new JSONArray();
                optionsList = Arrays.asList(answers);
                for (int i = 0; i < questions.length; i++) {
                    JSONObject optionObj = new JSONObject();
                    optionObj.put("name", questions[i]);
                    optionObj.put("isAnswer", optionsList.contains(questions[i].trim()) ? 1 : 0);
                    optionObj.put("indexId", i);
                    questionArray.add(optionObj);
                }

                // 分类
                Long questionTypeId = null;
                FsUserCourseCategory category = courseCategoryMapper.selectFsUserCourseCategoryByName(questionType);
                if (Objects.nonNull(category)) {
                    questionTypeId = category.getCateId();
                }

                FsCourseQuestionBank questionBank = new FsCourseQuestionBank();
                questionBank.setTitle(title);
                questionBank.setType(type.contains("单") ? 1L : 2L);
                questionBank.setQuestionType(questionTypeId);
                questionBank.setStatus(1L);
                questionBank.setSort(importDTO.getSort());
                questionBank.setQuestion(JSON.toJSONString(questionArray));
                questionBank.setAnswer(answers.length > 1 ? JSON.toJSONString(answers) : answer);
                questionBank.setCreateTime(new Date());
                questionBank.setCreateBy(nickName);
                fsCourseQuestionBankMapper.insertFsCourseQuestionBank(questionBank);

                importSuccessMsg.append("<br/>").append(successNum).append("、题目 ").append(title).append(" 导入成功");
                successNum++;
            } catch (Exception e) {
                String msg = "<br/>" + failureNum + "、题目 " + importDTO.getTitle() + " 导入异常：";
                importErrorMsg.append(msg).append(e.getMessage());
                failureNum++;
            }
        }

        // 在所有导入处理完成后，构建最终的导入结果消息
        importMsg.insert(0, "导入完成！成功" + successNum + " 条，失败" + failureNum + "条。");
        importMsg.append(importErrorMsg);
        importMsg.append(importSuccessMsg);
        return importMsg.toString();
    }

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


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