package jnpf.cultivate.v2.util;

import jnpf.model.cultivate.v2.exam.po.CultivateExam;
import jnpf.model.cultivate.v2.exam.po.CultivateExamDrawRule;
import jnpf.model.cultivate.v2.exam.req.V2SaveExamReq;

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

/**
 * 考试变更判定
 *
 * @author yanwenfu
 * @create 2026-04-22
 */
public class ExamChangeDetector {

    public static ExamChangeResult detect(
            CultivateExam oldExam,
            V2SaveExamReq newExam,
            List<CultivateExamDrawRule> oldRules,
            List<CultivateExamDrawRule> newRules) {

        ExamChangeResult result = new ExamChangeResult();
        result.setChangedFields(new ArrayList<>());

        // ===== 1. exam字段对比 =====
        boolean examChanged = compareExam(oldExam, newExam, result);

        // ===== 2. 抽题规则对比 =====
        boolean ruleChanged = hasRuleChanged(oldRules, newRules);

        if (ruleChanged) {
            result.markChanged("drawRule");
        }

        result.setExamChanged(examChanged);
        result.setRuleChanged(ruleChanged);
        result.setChanged(examChanged || ruleChanged);

        return result;
    }

    private static boolean compareExam(CultivateExam oldExam,
                                       V2SaveExamReq newExam,
                                       ExamChangeResult result) {

        if (oldExam == null && newExam == null) return false;
        if (oldExam == null || newExam == null) {
            result.markChanged("exam");
            return true;
        }

        boolean changed = false;

        if (!Objects.equals(oldExam.getExamType(), newExam.getExamType())) {
            result.markChanged("examType");
            changed = true;
        }

        if (!Objects.equals(oldExam.getStartTime(), newExam.getStartTime())) {
            result.markChanged("startTime");
            changed = true;
        }

        if (!Objects.equals(oldExam.getEndTime(), newExam.getEndTime())) {
            result.markChanged("endTime");
            changed = true;
        }

        if (!Objects.equals(oldExam.getExamLimitation(), newExam.getExamLimitation())) {
            result.markChanged("examLimitation");
            changed = true;
        }

        if (!Objects.equals(oldExam.getExamTime(), newExam.getExamTime())) {
            result.markChanged("examTime");
            changed = true;
        }

        if (!Objects.equals(oldExam.getDrawMode(), newExam.getDrawMode())) {
            result.markChanged("drawMode");
            changed = true;
        }

        if (!Objects.equals(oldExam.getDrawDataBase(), String.join(",", newExam.getDrawDataBaseList()))) {
            result.markChanged("drawDataBase");
            changed = true;
        }

        if (!Objects.equals(oldExam.getReExamFrequencyType(), newExam.getReExamFrequencyType())) {
            result.markChanged("reExamFrequencyType");
            changed = true;
        }

        if (!Objects.equals(oldExam.getReExamFrequencyNum(), newExam.getReExamFrequencyNum())) {
            result.markChanged("reExamFrequencyNum");
            changed = true;
        }

        if (!Objects.equals(oldExam.getPassType(), newExam.getPassType())) {
            result.markChanged("passType");
            changed = true;
        }

        if (!Objects.equals(oldExam.getPassMark(), newExam.getPassMark())) {
            result.markChanged("passMark");
            changed = true;
        }

        if (!Objects.equals(oldExam.getExcellentType(), newExam.getExcellentType())) {
            result.markChanged("excellentType");
            changed = true;
        }

        if (!Objects.equals(oldExam.getExcellentMark(), newExam.getExcellentMark())) {
            result.markChanged("excellentMark");
            changed = true;
        }

        return changed;
    }

    private static boolean isSameMember(String a, String b) {
        if (a == null && b == null) return true;
        if (a == null || b == null) return false;

        return normalize(a).equals(normalize(b));
    }

    private static List<String> normalize(String str) {
        return Arrays.stream(str.split(","))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .sorted()
                .collect(Collectors.toList());
    }

    // --------------------------------------------- 规则变更 -------------------------------------------
    public static boolean hasRuleChanged(List<CultivateExamDrawRule> oldList,
                                     List<CultivateExamDrawRule> newList) {

        // 都为空 → 无变更
        if (oldList == null && newList == null) return false;
        // 一个为空 → 有变更
        if (oldList == null || newList == null) return true;

        if (oldList.size() != newList.size()) return true;
        if (oldList.isEmpty()) return false;

        // 判断模式（看有没有 questionId）
        boolean isFixed = isFixedMode(oldList);

        if (isFixed != isFixedMode(newList)) {
            // 模式变了（随机 → 固定 / 固定 → 随机）
            return true;
        }

        return isFixed ? hasChangedFixed(oldList, newList) : hasChangedRandom(oldList, newList);
    }

    /**
     * 判断是否固定抽题
     */
    private static boolean isFixedMode(List<CultivateExamDrawRule> list) {
        return list.stream().anyMatch(r -> r.getQuestionId() != null && !r.getQuestionId().isEmpty());
    }

    /**
     * 固定抽题：比 questionId + score + questionType
     */
    private static boolean hasChangedFixed(List<CultivateExamDrawRule> oldList,
                                           List<CultivateExamDrawRule> newList) {

        Set<String> oldSet = oldList.stream()
                .map(ExamChangeDetector::buildFixedKey)
                .collect(Collectors.toSet());

        Set<String> newSet = newList.stream()
                .map(ExamChangeDetector::buildFixedKey)
                .collect(Collectors.toSet());

        return !oldSet.equals(newSet);
    }

    private static String buildFixedKey(CultivateExamDrawRule r) {
        return r.getQuestionType() + "_" +
                r.getQuestionId() + "_" +
                r.getScore();
    }

    /**
     * 随机抽题：按 questionType 唯一比配置
     */
    private static boolean hasChangedRandom(List<CultivateExamDrawRule> oldList,
                                            List<CultivateExamDrawRule> newList) {

        Map<Integer, CultivateExamDrawRule> oldMap = oldList.stream()
                .collect(Collectors.toMap(
                        CultivateExamDrawRule::getQuestionType,
                        r -> r
                ));

        Map<Integer, CultivateExamDrawRule> newMap = newList.stream()
                .collect(Collectors.toMap(
                        CultivateExamDrawRule::getQuestionType,
                        r -> r
                ));

        if (!oldMap.keySet().equals(newMap.keySet())) {
            return true;
        }

        for (Integer type : oldMap.keySet()) {
            CultivateExamDrawRule o = oldMap.get(type);
            CultivateExamDrawRule n = newMap.get(type);

            if (!Objects.equals(o.getPickCount(), n.getPickCount())) return true;
            if (!Objects.equals(o.getEasyCount(), n.getEasyCount())) return true;
            if (!Objects.equals(o.getMediumCount(), n.getMediumCount())) return true;
            if (!Objects.equals(o.getHardCount(), n.getHardCount())) return true;
            if (!Objects.equals(o.getScore(), n.getScore())) return true;
        }

        return false;
    }
}
