import models from "../models/index.js";
import response from "../response.js";

export const checkCorrectAnswers = async (req, res, next) => {
  const { id } = req.params;

  try {
    const stdExercises = await models.StdExercise.findAll({
      where: { ID_STUDENT_LEARNING: id },
    });

    if (!stdExercises || stdExercises.length === 0) {
      return response(404, null, "No student exercises found", res);
    }

    for (const stdExercise of stdExercises) {
      const { ID_ADMIN_EXERCISE, ANSWER_STUDENT } = stdExercise;

      const exercise = await models.Exercise.findByPk(ID_ADMIN_EXERCISE);
      if (!exercise) continue;

      const weight = parseFloat(exercise.SCORE_WEIGHT);
      const questionType = exercise.QUESTION_TYPE;

      switch (questionType) {
        case "MCQ": {
          const multipleChoice = await models.MultipleChoices.findOne({
            where: { ID_ADMIN_EXERCISE },
          });
          if (multipleChoice) {
            stdExercise.IS_CORRECT =
              ANSWER_STUDENT === multipleChoice.ANSWER_KEY ? 1 : 0;
            stdExercise.RESULT_SCORE_STUDENT =
              ANSWER_STUDENT === multipleChoice.ANSWER_KEY ? weight : 0.0;
          }
          break;
        }

        case "TFQ": {
          const trueFalse = await models.TrueFalse.findOne({
            where: { ID_ADMIN_EXERCISE },
          });
          if (trueFalse) {
            const isTrueStudent = ANSWER_STUDENT === "1";
            stdExercise.IS_CORRECT =
              isTrueStudent === Boolean(trueFalse.IS_TRUE) ? 1 : 0;
            stdExercise.RESULT_SCORE_STUDENT =
              isTrueStudent === Boolean(trueFalse.IS_TRUE) ? weight : 0.0;
          }
          break;
        }

        case "MPQ": {
          const matchingPairs = await models.MatchingPairs.findAll({
            where: { ID_ADMIN_EXERCISE },
          });
          if (matchingPairs && matchingPairs.length > 0) {
            const studentAnswers = ANSWER_STUDENT.split(",").map((pair) => {
              const [left, right] = pair.split("-");

              return {
                LEFT_PAIR: left ? left.trim() : "",
                RIGHT_PAIR: right ? right.trim() : "",
              };
            });

            let correctCount = 0;
            for (const studentAnswer of studentAnswers) {
              if (
                matchingPairs.some(
                  (pair) =>
                    pair.LEFT_PAIR === studentAnswer.LEFT_PAIR &&
                    pair.RIGHT_PAIR === studentAnswer.RIGHT_PAIR
                )
              ) {
                correctCount++;
              }
            }

            const correctPercentage = correctCount / matchingPairs.length;
            stdExercise.IS_CORRECT = correctCount > 0 ? 1 : 0;
            stdExercise.RESULT_SCORE_STUDENT = correctPercentage * weight;
          }
          break;
        }

        default:
          break;
      }

      await stdExercise.save();
    }

    next();
  } catch (error) {
    console.error("Error checking correct answers:", error);
    response(500, null, "Internal Server Error", res);
  }
};

export const calculateScore = async (req, res, next) => {
  const { id } = req.params;

  try {
    const stdLearning = await models.StdLearning.findByPk(id);

    if (!stdLearning) {
      return response(404, null, "Student Learning record not found", res);
    }

    const allExercises = await models.Exercise.findAll({
      where: {
        ID_LEVEL: stdLearning.ID_LEVEL,
        IS_DELETED: 0,
      },
    });

    if (!allExercises || allExercises.length === 0) {
      return response(404, null, "No exercises found for this level", res);
    }

    const stdExercises = await models.StdExercise.findAll({
      where: { ID_STUDENT_LEARNING: id },
    });

    let totalWeight = 0;
    for (const exercise of allExercises) {
      totalWeight += exercise.SCORE_WEIGHT;
    }

    let totalScore = 0;
    for (const stdExercise of stdExercises) {
      const exercise = allExercises.find(
        (ex) => ex.ID_ADMIN_EXERCISE === stdExercise.ID_ADMIN_EXERCISE
      );

      if (exercise && stdExercise.RESULT_SCORE_STUDENT !== null) {
        totalScore += stdExercise.RESULT_SCORE_STUDENT;
      }
    }

    const finalScore = Math.round((totalScore / totalWeight) * 100);

    req.body.SCORE = finalScore;

    next();
  } catch (error) {
    console.log(error);
    response(500, null, "Internal Server Error", res);
  }
};

export const checkFirstFiveCorrect = async (req, res, next) => {
  const { id } = req.params;

  try {
    const stdLearning = await models.StdLearning.findByPk(id);

    if (!stdLearning) {
      return response(404, null, "Student Learning record not found", res);
    }

    const firstFiveExercises = await models.Exercise.findAll({
      where: {
        ID_LEVEL: stdLearning.ID_LEVEL,
        IS_DELETED: 0,
      },
      order: [
        [
          models.Sequelize.literal(
            "CAST(SUBSTRING_INDEX(TITLE, ' ', -1) AS UNSIGNED)"
          ),
          "ASC",
        ],
      ],
      limit: 5,
    });

    if (!firstFiveExercises || firstFiveExercises.length < 5) {
      return response(404, null, "Not enough exercises for this level", res);
    }

    const stdExercises = await models.StdExercise.findAll({
      where: { ID_STUDENT_LEARNING: id },
    });

    const allCorrect = firstFiveExercises.every((exercise) => {
      const stdExercise = stdExercises.find(
        (se) => se.ID_ADMIN_EXERCISE === exercise.ID_ADMIN_EXERCISE
      );
      return stdExercise && stdExercise.IS_CORRECT === 1;
    });

    req.body.FIRST_FIVE_CORRECT = allCorrect;

    next();
  } catch (error) {
    console.error("Error checking first five correct answers:", error);
    res.status(500).json({ message: "Internal Server Error" });
  }
};

export const nextLearning = async (req, res, next) => {
  const { SCORE, FIRST_FIVE_CORRECT } = req.body;

  try {
    const stdLearning = await models.StdLearning.findByPk(req.params.id, {
      include: [
        {
          model: models.Level,
          as: "level",
        },
      ],
    });

    if (!stdLearning) {
      return response(404, null, "Student Learning record not found", res);
    }

    const topic_id = stdLearning.level.ID_TOPIC;

    const levels = await models.Level.findAll({
      where: {
        ID_TOPIC: topic_id,
        IS_DELETED: 0,
      },
      order: [["NAME_LEVEL", "ASC"]],
    });

    const levelMap = levels.reduce((map, level) => {
      map[level.NAME_LEVEL] = level;
      return map;
    }, {});

    let nextLearningLevel = null;
    let currentLevelNumber = parseInt(
      stdLearning.level.NAME_LEVEL.split(" ")[1]
    );

    if (stdLearning.level.IS_PRETEST) {
      if (SCORE >= 0 && SCORE <= 50) {
        nextLearningLevel = levelMap["Level 1"];
      } else if (SCORE >= 51 && SCORE <= 60) {
        nextLearningLevel = levelMap["Level 2"];
      } else if (SCORE >= 61 && SCORE <= 70) {
        nextLearningLevel = levelMap["Level 3"];
      } else if (SCORE >= 71 && SCORE <= 80) {
        nextLearningLevel = levelMap["Level 4"];
      } else if (SCORE >= 81 && SCORE <= 90) {
        nextLearningLevel = levelMap["Level 5"];
      } else if (SCORE >= 91 && SCORE <= 100) {
        nextLearningLevel = levelMap["Level 6"];
      }
    } else {
      if (SCORE >= 75 && FIRST_FIVE_CORRECT) {
        currentLevelNumber += SCORE >= 85 ? 2 : 1;
        currentLevelNumber = Math.min(6, currentLevelNumber);
      } else if (
        (SCORE >= 75 && !FIRST_FIVE_CORRECT) ||
        (SCORE >= 51 && SCORE <= 74)
      ) {
        currentLevelNumber = currentLevelNumber;
      } else if (SCORE >= 41 && SCORE <= 50) {
        currentLevelNumber = Math.max(1, currentLevelNumber - 1);
      } else if (SCORE >= 0 && SCORE <= 40) {
        currentLevelNumber = Math.max(1, currentLevelNumber - 2);
      }

      currentLevelNumber = Math.max(1, Math.min(6, currentLevelNumber));

      nextLearningLevel = levelMap[`Level ${currentLevelNumber}`];
    }

    if (!nextLearningLevel) {
      return response(404, null, "Next learning level not found", res);
    }

    req.body.NEXT_LEARNING = nextLearningLevel.ID_LEVEL;
    req.body.IS_PASS =
      SCORE > 85 &&
      stdLearning.level.NAME_LEVEL === "Level 6" &&
      FIRST_FIVE_CORRECT
        ? 1
        : 0;

    next();
  } catch (error) {
    console.log(error);
    response(500, null, "Error determining next learning path", res);
  }
};
