package jnpf.cultivate.v2.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import jnpf.base.UserInfo;
import jnpf.model.cultivate.req.questionbank.QuestionOptionReq;
import jnpf.model.cultivate.resp.ExcelImportQuestionResultReq;
import jnpf.model.cultivate.resp.ExcelUserQuestionVo;
import jnpf.model.cultivate.resp.QuestionOptionVo;
import jnpf.model.cultivate.resp.UserQuestionVo;
import jnpf.model.cultivate.v2.question.req.V2AddQuestionReq;
import jnpf.model.cultivate.v2.question.req.V2EditQuestionReq;
import jnpf.model.cultivate.v2.question.req.V2ExcelImportQuestionResultReq;
import jnpf.model.enums.CourseEnums;
import jnpf.model.personnels.dto.staff.roster.WorkerGroupDataDto;
import jnpf.util.UserProvider;
import jnpf.util.excel.EasyExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
public class V2QuestionExcelExportUtil {

    final static String FTB_QUESTION_IMPORT_SHEET_KEY = "qtn:import::%s:%s";

    public static <T> void questionExportExcel(HttpServletResponse response, String fileName, List<T> list, Class<T> tClass) throws IOException {
        String fileRealName = URLEncoder.encode(fileName + System.currentTimeMillis() / 1000, "UTF-8").replaceAll("\\+", "%20");
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileRealName + ".xlsx");


            ExcelWriterBuilder write = EasyExcel.write(outputStream, tClass);
            write.registerWriteHandler(new EasyExcelUtils.CustomCellWriteHandler()).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).inMemory(true);
            write.sheet("sheet1").doWrite(list);

        }
    }

    public static <T> void questionExportExcel1(HttpServletResponse response, String fileName, List<T> list, Class<T> tClass) throws IOException {
        String fileRealName = URLEncoder.encode(fileName + System.currentTimeMillis() / 1000, "UTF-8").replaceAll("\\+", "%20");
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileRealName + ".xlsx");
            String template = "https://jnpf-resource-1304460613.cos.ap-chengdu.myqcloud.com/xgl/questionExportTemplate.xlsx";
            File localFile = downloadFile(template);


            // 这里 会填充到第一个sheet， 然后文件流会自动关闭
            EasyExcel.write(outputStream).withTemplate(localFile).sheet("Sheet1").doFill(list);


        }
    }

    public static File downloadFile(String template) {

        // 本地保存的路径及文件名
        String savePath = "./" + System.currentTimeMillis() + "/questionExportTemplate.xlsx"; // 请根据实际情况修改

        try {
            // 下载文件
            File file = FileUtil.writeBytes(HttpUtil.downloadBytes(template), FileUtil.file(savePath));
            return file;

        } catch (Exception e) {
            System.err.println("文件下载失败：" + e.getMessage());
            return null;
        }
    }


    public static List<ExcelUserQuestionVo> convertQuestionList(List<UserQuestionVo> userQuestionVoList) {
        List<ExcelUserQuestionVo> list = new ArrayList<>();
        for (UserQuestionVo userQuestionVo : userQuestionVoList) {
            ExcelUserQuestionVo excelUserQuestionVo = toExcelUserQuestionVo(userQuestionVo);
            list.add(excelUserQuestionVo);
        }
        return list;
    }

    private static ExcelUserQuestionVo toExcelUserQuestionVo(UserQuestionVo userQuestionVo) {
        ExcelUserQuestionVo vo = new ExcelUserQuestionVo();
        CourseEnums.QuestionType type = CourseEnums.QuestionType.fromCode(userQuestionVo.getType());
        if (null != type) {
            vo.setType(type.getDesc());
        }

        CourseEnums.QuestionDifficulty difficulty = CourseEnums.QuestionDifficulty.fromCode(userQuestionVo.getDifficulty());
        if (null != difficulty) {
            vo.setDifficulty(difficulty.getDesc());
        }
        List<QuestionOptionVo> questionOptionVoList = new ArrayList<>();
        switch (type) {
            case SINGLE://单选
            case JUDGE://判断
            case MULTI://多选
            case ONE_OR_MULTI://不定项
                questionOptionVoList = userQuestionVo.getQuestionOptionVoList();
                if (CollUtil.isNotEmpty(questionOptionVoList)) {
                    List<String> rightAnsters = new ArrayList<>();
                    for (int i = 0; i < questionOptionVoList.size(); i++) {
                        String right = setOptionValue(questionOptionVoList.get(i), vo, i);
                        if (StringUtils.isNotEmpty(right)) {
                            rightAnsters.add(right);
                        }
                    }
                    vo.setUserAnswer(StringUtils.join(rightAnsters, ","));
                }
                break;
            case FILL://填空题
                questionOptionVoList = userQuestionVo.getQuestionOptionVoList();
                if (CollUtil.isNotEmpty(questionOptionVoList)) {
                    for (int i = 0; i < questionOptionVoList.size(); i++) {
                        String right = setOptionValue(questionOptionVoList.get(i), vo, i);
                    }
                }
                break;

        }

        vo.setContent(userQuestionVo.getContent());
        vo.setAnalysis(userQuestionVo.getAnalysis());

        return vo;
    }


    private static String setOptionValue(QuestionOptionVo questionOptionVo, ExcelUserQuestionVo vo, Integer i) {
        String optionValue = questionOptionVo.getContent();
        Integer isRightOption = questionOptionVo.getIsRightOption();
        return setRightAnswerAndFillOption(optionValue, isRightOption, vo, i);
    }

    private static String setErrorOptionValue(QuestionOptionReq questionOptionVo, ExcelUserQuestionVo vo, Integer i) {
        String optionValue = questionOptionVo.getContent();
        Integer isRightOption = questionOptionVo.getIsRightOption();
        return setRightAnswerAndFillOption(optionValue, isRightOption, vo, i);
    }

    private static String setRightAnswerAndFillOption(String optionValue, Integer isRightOption, ExcelUserQuestionVo vo, Integer i) {
        String right = "";
        switch (i) {
            case 0:
                vo.setOptionA(optionValue);
                if (isRightOption == 1) {
                    right = "A";
                }
                break;
            case 1:
                vo.setOptionB(optionValue);
                if (isRightOption == 1) {
                    right = "B";
                }
                break;
            case 2:
                vo.setOptionC(optionValue);
                if (isRightOption == 1) {
                    right = "C";
                }
                break;
            case 3:
                vo.setOptionD(optionValue);
                if (isRightOption == 1) {
                    right = "D";
                }
                break;
            case 4:
                vo.setOptionE(optionValue);
                if (isRightOption == 1) {
                    right = "E";
                }
                break;
            case 5:
                vo.setOptionF(optionValue);
                if (isRightOption == 1) {
                    right = "F";
                }
                break;
            case 6:
                vo.setOptionG(optionValue);
                if (isRightOption == 1) {
                    right = "G";
                }
                break;
            case 7:
                vo.setOptionH(optionValue);
                if (isRightOption == 1) {
                    right = "H";
                }
                break;
            default:
                break;
        }
        return right;
    }


    public static void dealFillQuestion(List<V2ExcelImportQuestionResultReq> allQuestionList) {
        for (V2ExcelImportQuestionResultReq addQuestionReq : allQuestionList) {
            checkOneQuestion(addQuestionReq);
        }
    }

    public static void checkOneQuestion(V2ExcelImportQuestionResultReq addQuestionReq) {
        String content = addQuestionReq.getContent();
        if (StringUtils.isEmpty(content)) {
            addQuestionReq.setMsg("题目内容不能为空");
            addQuestionReq.setSuccess(1);
            return;
        }
        if (content.length() > 200) {
            addQuestionReq.setMsg("题目内容长度不能大于200个字符");
            addQuestionReq.setSuccess(1);
            return;
        }
        if (StringUtils.isNotEmpty(addQuestionReq.getAnalysis())) {
            if (addQuestionReq.getAnalysis().length() > 1000) {
                addQuestionReq.setMsg("题目解析长度不能大于1000个字符");
                addQuestionReq.setSuccess(1);
                return;
            }
        }

        List<QuestionOptionReq> optionList = addQuestionReq.getOptionList();
        if (CollUtil.isNotEmpty(optionList)) {
            if (optionList.size() > 8) {
                addQuestionReq.setMsg("选项不能大于 8 个");
                addQuestionReq.setSuccess(1);
                return;
            }
            for (QuestionOptionReq optionReq : optionList) {
                if (StringUtils.isNotEmpty(optionReq.getContent())) {
                    if (optionReq.getContent().length() > 200) {
                        addQuestionReq.setMsg("题目选项的内容不能大于200个字符");
                        addQuestionReq.setSuccess(1);
                        return;
                    }
                }
            }
        }
        // 根据题型进行验证
        CourseEnums.QuestionType questionType = CourseEnums.QuestionType.fromCode(addQuestionReq.getType());
        if (questionType == null) {
            addQuestionReq.setMsg("题目类型无效");
            addQuestionReq.setSuccess(1);
            return;
        }

        switch (questionType) {
            case FILL: {
                checkFill(addQuestionReq, content, optionList);
                break;
            }
            case MULTI: {
                checkMulti(addQuestionReq, optionList);
                break;
            }
            case ONE_OR_MULTI: {
                checkOneOrMulti(addQuestionReq, optionList);
                break;
            }
            case SINGLE: {
                checkSingle(addQuestionReq, optionList);
                break;
            }
            case JUDGE: {
                checkJudge(addQuestionReq, optionList);
                break;
            }
            case INPUT: {
                break;
            }
            default: {
            }
        }
    }

    private static void checkJudge(V2ExcelImportQuestionResultReq addQuestionReq, List<QuestionOptionReq> optionList) {
        if (CollUtil.isEmpty(optionList)) {
            addQuestionReq.setMsg("判断题选项不能为空");
            addQuestionReq.setSuccess(1);
            return;
        }
        if (optionList.size() != 2) {
            addQuestionReq.setMsg("判断题选项选项只能是 2 个");
            addQuestionReq.setSuccess(1);
            return;
        }

        int num = 0;
        for (QuestionOptionReq optionReq : optionList) {
            if (optionReq.getIsRightOption() != null && optionReq.getIsRightOption() == 1) {
                num++;
            }
        }
        if (num > 1) {
            addQuestionReq.setMsg("判断题正确答案应该只有 1 个");
            addQuestionReq.setSuccess(1);
            return;
        }
        if (num == 0) {
            addQuestionReq.setMsg("判断题必须有 1 个正确答案");
            addQuestionReq.setSuccess(1);
            return;
        }
    }

    private static void checkSingle(V2ExcelImportQuestionResultReq addQuestionReq, List<QuestionOptionReq> optionList) {
        if (CollUtil.isEmpty(optionList)) {
            addQuestionReq.setMsg("单选题选项不能为空");
            addQuestionReq.setSuccess(1);
            return;
        }
        if (optionList.size() < 2) {
            addQuestionReq.setMsg("单选题选项不能少于 2 个");
            addQuestionReq.setSuccess(1);
            return;
        }

        int num = 0;
        for (QuestionOptionReq optionReq : optionList) {
            if (optionReq.getIsRightOption() != null && optionReq.getIsRightOption() == 1) {
                num++;
            }
        }
        if (num != 1) {
            addQuestionReq.setMsg("单选题正确答案应该只有 1 个");
            addQuestionReq.setSuccess(1);
            return;
        }
    }

    private static void checkOneOrMulti(V2ExcelImportQuestionResultReq addQuestionReq, List<QuestionOptionReq> optionList) {
        if (CollUtil.isEmpty(optionList)) {
            addQuestionReq.setMsg("不定向选择题选项不能为空");
            addQuestionReq.setSuccess(1);
            return;
        }
        if (optionList.size() < 2) {
            addQuestionReq.setMsg("不定向选择题选项不能少于 2 个");
            addQuestionReq.setSuccess(1);
            return;
        }

        int num = 0;
        for (QuestionOptionReq optionReq : optionList) {
            if (optionReq.getIsRightOption() != null && optionReq.getIsRightOption() == 1) {
                num++;
            }
        }
        if (num < 1) {
            addQuestionReq.setMsg("不定项选择题正确答案不能小于 1 个");
            addQuestionReq.setSuccess(1);
            return;
        }
    }

    private static void checkMulti(V2ExcelImportQuestionResultReq addQuestionReq, List<QuestionOptionReq> optionList) {
        if (CollUtil.isEmpty(optionList)) {
            addQuestionReq.setMsg("多选题选项不能为空");
            addQuestionReq.setSuccess(1);
            return;
        }
        if (optionList.size() < 2) {
            addQuestionReq.setMsg("多选题选项不能少于 2 个");
            addQuestionReq.setSuccess(1);
            return;
        }

        int num = 0;
        for (QuestionOptionReq optionReq : optionList) {
            if (optionReq.getIsRightOption() != null && optionReq.getIsRightOption() == 1) {
                num++;
            }
        }
        if (num < 2) {
            addQuestionReq.setMsg("多选题正确答案不能小于 2 个");
            addQuestionReq.setSuccess(1);
            return;
        }
    }

    private static void checkFill(V2ExcelImportQuestionResultReq addQuestionReq, String content, List<QuestionOptionReq> optionList) {
        int count = countUnderscoresConsideringAdjacentAsOne(content);
        if (optionList.size() > count) {
            addQuestionReq.setOptionList(optionList.subList(0, count));
        } else if (optionList.size() < count) {
            long size = optionList.size();
            for (int i = 0; i < count - size; i++) {
                QuestionOptionReq optionReq = new QuestionOptionReq();
                optionReq.setContent("");
                optionReq.setSortCode(size + i);
                addQuestionReq.getOptionList().add(optionReq);
            }
        }
        if (!addQuestionReq.getContent().contains("()") && !addQuestionReq.getContent().contains("（ ）")) {
            addQuestionReq.setMsg("填空题题目必须包含括号");
            addQuestionReq.setSuccess(1);
            return;
        }
    }

    public static int countUnderscoresConsideringAdjacentAsOne(String str) {
        // 使用正则表达式替换连续的下划线为单个下划线
        String normalizedStr = str.replaceAll("\\(+", "(");
        normalizedStr = normalizedStr.replaceAll("\\)+", ")");
        normalizedStr = normalizedStr.replaceAll("\\（+", "(");
        normalizedStr = normalizedStr.replaceAll("\\）+", ")");
        // 遍历处理后的字符串，计算下划线数量
        int count = 0;
        for (int i = 0; i < normalizedStr.length(); i++) {
            if (normalizedStr.charAt(i) == '(') {
                count++;
            }
        }
        return count;
    }

    public static String qeneralQuestionImportKey() {
        String loginUserId = UserProvider.getLoginUserId();
        String tenantId = getTenantId();
        return String.format(FTB_QUESTION_IMPORT_SHEET_KEY, tenantId, loginUserId);
    }

    public static List<String> getOrgIds(List<WorkerGroupDataDto> workerGroupDataDtoList) {
        if (CollUtil.isEmpty(workerGroupDataDtoList)) {
            return new ArrayList<>();
        }

        List<String> list = new ArrayList<>();
        for (WorkerGroupDataDto workerGroupDataDto : workerGroupDataDtoList) {
            if (StringUtils.isNotEmpty(workerGroupDataDto.getAffiliatedOrg())) {
                list.add(workerGroupDataDto.getAffiliatedOrg());
            }
        }
        return list;
    }

    public List<String> uniqueStringList(List<String> list) {
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list.stream().filter(Objects::nonNull) // 过滤掉 null 值
                .filter(str -> !str.isEmpty()) // 过滤掉空字符串
                .distinct() // 去重
                .collect(Collectors.toList()); // 收集为 List
    }

    public static List<String> stringToList(String str, String split) {
        if (StringUtils.isEmpty(str)) {
            return new ArrayList<>();
        }
        return Arrays.asList(str.split(split));
    }

    public static List<ExcelUserQuestionVo> convertErrorQuestionList(List<ExcelImportQuestionResultReq> errorList) {
        List<ExcelUserQuestionVo> list = new ArrayList<>();
        for (ExcelImportQuestionResultReq userQuestionVo : errorList) {
            ExcelUserQuestionVo excelUserQuestionVo = toErrorExcelUserQuestionVo(userQuestionVo);
            list.add(excelUserQuestionVo);
        }
        return list;
    }

    private static ExcelUserQuestionVo toErrorExcelUserQuestionVo(ExcelImportQuestionResultReq userQuestionVo) {
        ExcelUserQuestionVo vo = new ExcelUserQuestionVo();
        CourseEnums.QuestionType type = CourseEnums.QuestionType.fromCode(userQuestionVo.getType());
        if (null != type) {
            vo.setType(type.getDesc());
        }

        CourseEnums.QuestionDifficulty difficulty = CourseEnums.QuestionDifficulty.fromCode(userQuestionVo.getDifficulty());
        if (null != difficulty) {
            vo.setDifficulty(difficulty.getDesc());
        }
        List<QuestionOptionReq> questionOptionVoList = new ArrayList<>();
        switch (type) {
            case SINGLE://单选
            case JUDGE://判断
            case MULTI://多选
            case ONE_OR_MULTI://不定项
                questionOptionVoList = userQuestionVo.getOptionList();
                if (CollUtil.isNotEmpty(questionOptionVoList)) {
                    List<String> rightAnsters = new ArrayList<>();
                    for (int i = 0; i < questionOptionVoList.size(); i++) {
                        String right = setErrorOptionValue(questionOptionVoList.get(i), vo, i);
                        if (StringUtils.isNotEmpty(right)) {
                            rightAnsters.add(right);
                        }
                    }
                    vo.setUserAnswer(StringUtils.join(rightAnsters, ","));
                }
                break;
            case FILL://填空题
                questionOptionVoList = userQuestionVo.getOptionList();
                if (CollUtil.isNotEmpty(questionOptionVoList)) {
                    for (int i = 0; i < questionOptionVoList.size(); i++) {
                        String right = setErrorOptionValue(questionOptionVoList.get(i), vo, i);
                    }
                }
                break;

        }

        vo.setContent(userQuestionVo.getContent());
        vo.setAnalysis(userQuestionVo.getAnalysis());

        return vo;
    }

    public static void checkAddQuestionParam(V2AddQuestionReq req) {
        V2ExcelImportQuestionResultReq excelImportQuestionResultReq = BeanUtil.copyProperties(req, V2ExcelImportQuestionResultReq.class);
        checkOneQuestion(excelImportQuestionResultReq);
        if (excelImportQuestionResultReq.getSuccess() == 1) {
            throw new RuntimeException(excelImportQuestionResultReq.getMsg());
        }
    }

    public static void checkEditQuestionParam(V2EditQuestionReq req) {
        V2ExcelImportQuestionResultReq excelImportQuestionResultReq = BeanUtil.copyProperties(req, V2ExcelImportQuestionResultReq.class);
        checkOneQuestion(excelImportQuestionResultReq);
        if (excelImportQuestionResultReq.getSuccess() == 1) {
            throw new RuntimeException(excelImportQuestionResultReq.getMsg());
        }
    }

    public static String getTenantId() {
        UserInfo userInfo = UserProvider.getUser();
        return userInfo.getTenantId();
    }
}
