package service;

import model.Question;
import model.User;
import model.UserType;
import service.generator.*;

import java.io.PrintWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;

public class ExamManager {
    private final Map<UserType, QuestionGenerator> generators = new HashMap<>();

    public ExamManager() {
        generators.put(UserType.PRIMARY, new PrimaryQuestionGenerator());
        generators.put(UserType.JUNIOR, new JuniorQuestionGenerator());
        generators.put(UserType.SENIOR, new SeniorQuestionGenerator());
    }

    public List<Question> generateExam(User user, UserType userType, int count) {
        QuestionGenerator generator = generators.get(userType);
        if (generator == null) throw new IllegalArgumentException("不支持的用户类型");

        List<Question> questions = new ArrayList<>();
        Set<String> generatedTexts = new HashSet<>();
        int maxAttempts = count * 20;
        int attempts = 0;

        while (questions.size() < count && attempts < maxAttempts) {
            String qText = generator.generateQuestion();
            if (generatedTexts.contains(qText)) {
                attempts++;
                continue;
            }
            try {
                double answer = ExpressionEvaluator.evaluate(qText);
                if (Double.isInfinite(answer) || Double.isNaN(answer)) continue;

                List<String> options = generateOptions(answer); // 调用已优化的方法
                int correctIndex = options.indexOf(formatAnswer(answer));

                questions.add(new Question(qText, options, correctIndex));
                generatedTexts.add(qText);
            } catch (Exception e) {

            } finally {
                attempts++;
            }
        }

        if (!questions.isEmpty()) {
            saveExamToFile(user, questions);
        }

        return questions;
    }


    private List<String> generateOptions(double correctAnswer) {
        Set<String> options = new LinkedHashSet<>();
        options.add(formatAnswer(correctAnswer));
        Random rand = new Random();

        // 判断答案是否为整数
        boolean isIntegerAnswer = Math.abs(correctAnswer - Math.round(correctAnswer)) < 1e-9;

        while (options.size() < 4) {
            String distractorStr;
            if (isIntegerAnswer) {

                int intAnswer = (int) Math.round(correctAnswer);
                int distractor;
                int type = rand.nextInt(3); // 三种整数干扰策略

                switch(type) {
                    case 0: // 策略一：在答案附近加减一个较小的随机数
                        distractor = intAnswer + (rand.nextInt(8) + 1) * (rand.nextBoolean() ? 1 : -1);
                        break;
                    case 1: // 策略二：模拟看错位的错误（加减10）
                        distractor = intAnswer + (rand.nextBoolean() ? 10 : -10);
                        break;
                    default: // 策略三：颠倒个位和十位（如果答案是两位数）
                        if (intAnswer >= 10 && intAnswer <= 99) {
                            distractor = (intAnswer % 10) * 10 + (intAnswer / 10);
                        } else {
                            // 如果不是两位数，则使用策略一
                            distractor = intAnswer + (rand.nextInt(8) + 1) * (rand.nextBoolean() ? 1 : -1);
                        }
                        break;
                }

                // 确保干扰项不等于正确答案
                if (distractor == intAnswer) {
                    distractor++;
                }
                distractorStr = String.valueOf(distractor);

            } else {
                double distractor;
                if (rand.nextBoolean()) { // 乘法干扰
                    distractor = correctAnswer * (rand.nextDouble() * 1.5 + 0.5);
                } else { // 临近值干扰
                    distractor = correctAnswer + (rand.nextDouble() - 0.5) * Math.max(1, Math.abs(correctAnswer * 0.2));
                }
                distractorStr = formatAnswer(distractor);
            }

            // 确保选项不重复
            if (!options.contains(distractorStr)) {
                options.add(distractorStr);
            }
        }

        List<String> shuffledOptions = new ArrayList<>(options);
        Collections.shuffle(shuffledOptions);
        return shuffledOptions;
    }

    private void saveExamToFile(User user, List<Question> questions) {
        try {
            Path userExamDir = Paths.get("exams", user.getEmail());
            Files.createDirectories(userExamDir);

            String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            Path examFile = userExamDir.resolve("exam_" + timestamp + ".txt");

            try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(examFile, StandardCharsets.UTF_8))) {
                writer.println("用户: " + user.getEmail());
                writer.println("时间: " + new Date());
                writer.println("题目类型: " + user.getUserType().getDisplayName());
                writer.println("题目数量: " + questions.size());
                writer.println("========================================");
                writer.println();

                for (int i = 0; i < questions.size(); i++) {
                    Question q = questions.get(i);
                    writer.println((i + 1) + ". " + q.getQuestionText());

                    List<String> options = q.getOptions();
                    char optionLabel = 'A';
                    for (int j = 0; j < options.size(); j++) {
                        writer.println("   " + optionLabel + ". " + options.get(j));
                        optionLabel++;
                    }

                    writer.println("   正确答案: " + (char)('A' + q.getCorrectOptionIndex()));
                    writer.println();
                }
            }
            System.out.println("试卷已成功保存至: " + examFile.toAbsolutePath());
        } catch (IOException e) {
            System.err.println("保存试卷文件时出错: " + e.getMessage());
        }
    }

    private String formatAnswer(double number) {
        if (Math.abs(number - Math.round(number)) < 1e-9) {
            return String.valueOf((long) Math.round(number));
        } else {
            return String.format("%.2f", number);
        }
    }
}