import response from "../../response.js";
import models from "../../models/index.js";
import { createMonitoring } from "../monitoringControllers/monitoring.js";

export const getStdLearnings = async (req, res) => {
  try {
    const stdLearning = await models.StdLearning.findAll();
    response(200, stdLearning, "Success", res);
  } catch (error) {
    console.log(error);
    response(500, null, "Error retrieving student learning data!", res);
  }
};

export const getStdLearningById = async (req, res) => {
  try {
    const { id } = req.params;
    const stdLearning = await models.StdLearning.findByPk(id);

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

    response(200, stdLearning, "Success", res);
  } catch (error) {
    response(500, null, "Internal Server Error", res);
  }
};

export const createStdLearning = async (req, res) => {
  const { ID_LEVEL } = req.body;

  if (!req.user) {
    return response(401, null, "User not authenticated", res);
  }

  const ID = req.user.ID;

  try {
    if (req.stdLearning) {
      return response(
        200,
        req.stdLearning,
        "Student Learning data found and reused",
        res
      );
    }

    const level = await models.Level.findByPk(ID_LEVEL);
    if (!level) {
      return response(404, null, "Level not found", res);
    }

    const newStdLearning = await models.StdLearning.create({
      ID,
      ID_LEVEL,
    });

    response(
      201,
      newStdLearning,
      "Student Learning data created successfully",
      res
    );
  } catch (error) {
    console.log(error);
    response(500, null, "Internal Server Error", res);
  }
};

export const updateStdLearningById = async (req, res) => {
  const { id } = req.params;
  const { FEEDBACK_STUDENT } = req.body;

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

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

    if (req.user.ID !== stdLearning.ID) {
      return response(403, null, "Unauthorized to update this record", res);
    }

    stdLearning.STUDENT_FINISH = new Date();
    stdLearning.SCORE = req.body.SCORE || stdLearning.SCORE;
    stdLearning.NEXT_LEARNING =
      req.body.NEXT_LEARNING || stdLearning.NEXT_LEARNING;
    stdLearning.IS_PASS = req.body.IS_PASS || stdLearning.IS_PASS;

    if (FEEDBACK_STUDENT) {
      stdLearning.FEEDBACK_STUDENT = FEEDBACK_STUDENT;
    }

    await stdLearning.save();

    const level6 = await models.Level.findOne({
      where: {
        NAME_LEVEL: "Level 6",
        ID_TOPIC: stdLearning.level.ID_TOPIC,
      },
    });

    if (!level6) {
      return response(404, null, "Level 6 not found", res);
    }

    if (
      stdLearning.level.ID_LEVEL === level6.ID_LEVEL &&
      stdLearning.IS_PASS === 1
    ) {
      req.body.ID_STUDENT_LEARNING = id;

      const existingMonitoring = await models.Monitoring.findOne({
        where: { ID_STUDENT_LEARNING: id },
      });

      if (!existingMonitoring) {
        const newMonitoring = await createMonitoring(req);

        const { level, ...responseData } = stdLearning.toJSON();

        const combinedPayload = {
          ...responseData,
          MONITORING: newMonitoring,
        };

        return response(
          200,
          combinedPayload,
          "Student Learning record updated and monitoring created successfully",
          res
        );
      }
    } else {
      const monitoringToDelete = await models.Monitoring.findOne({
        where: { ID_STUDENT_LEARNING: id },
      });

      if (monitoringToDelete) {
        await monitoringToDelete.destroy();
      }
    }

    const { level, ...responseData } = stdLearning.toJSON();

    response(
      200,
      responseData,
      "Student Learning record updated successfully",
      res
    );
  } catch (error) {
    console.log(error);
    response(500, null, "Internal Server Error", res);
  }
};

export const learningScoreByStdLearningId = async (req, res) => {
  try {
    if (!req.user) {
      return response(401, null, "User not authenticated", res);
    }

    const { ID } = req.user;
    const { stdLearningId } = req.params;

    const stdLearning = await models.StdLearning.findOne({
      where: {
        ID_STUDENT_LEARNING: stdLearningId,
        ID: ID,
      },
      include: [
        {
          model: models.Level,
          as: "level",
          attributes: ["ID_LEVEL", "NAME_LEVEL"],
        },
        {
          model: models.Level,
          as: "nextLevel",
          attributes: ["NAME_LEVEL"],
        },
        {
          model: models.User,
          as: "learningUser",
          attributes: ["NAME_USERS"],
          include: [
            {
              model: models.Student,
              as: "students",
              attributes: ["NISN"],
            },
          ],
        },
      ],
    });

    if (!stdLearning) {
      return response(
        404,
        null,
        "No matching learning data found for this user",
        res
      );
    }

    if (!stdLearning.NEXT_LEARNING || !stdLearning.nextLevel) {
      return response(200, null, "No next learning level found", res);
    }

    const nextLearningData = {
      ID_STUDENT_LEARNING: stdLearning.ID_STUDENT_LEARNING,
      NAME_USERS: stdLearning.learningUser.NAME_USERS,
      NISN: stdLearning.learningUser.students
        ? stdLearning.learningUser.students.NISN
        : null,
      ID_LEVEL: stdLearning.level ? stdLearning.level.ID_LEVEL : null,
      CURRENT_LEVEL_NAME: stdLearning.level
        ? stdLearning.level.NAME_LEVEL
        : null,
      SCORE: stdLearning.SCORE,
      NEXT_LEARNING: stdLearning.NEXT_LEARNING,
      NEXT_LEARNING_NAME: stdLearning.nextLevel.NAME_LEVEL,
      IS_PASS: stdLearning.IS_PASS,
    };

    return response(200, nextLearningData, "Success", res);
  } catch (error) {
    console.log(error);
    return response(500, null, "Internal Server Error", res);
  }
};

export const learningHistory = async (req, res) => {
  const { page = 1, limit = 10 } = req.query;

  try {
    if (!req.user) {
      return response(401, null, "User not authenticated", res);
    }

    const { ID } = req.user;

    const stdLearnings = await models.StdLearning.findAll({
      where: {
        ID,
        STUDENT_FINISH: {
          [models.Sequelize.Op.ne]: null,
        },
        SCORE: {
          [models.Sequelize.Op.ne]: null,
        },
        NEXT_LEARNING: {
          [models.Sequelize.Op.ne]: null,
        },
      },
      include: [
        {
          model: models.Level,
          as: "level",
          include: [
            {
              model: models.Topic,
              as: "levelTopic",
              required: true,
              include: [
                {
                  model: models.Section,
                  as: "topicSection",
                  required: true,
                },
              ],
            },
          ],
          required: true,
        },
      ],
      order: [["STUDENT_FINISH", "DESC"]],
    });

    if (!stdLearnings.length) {
      return response(
        404,
        null,
        "No learning history found for this user",
        res
      );
    }

    const formattedLearnings = await Promise.all(
      stdLearnings.map(async (learning) => {
        let nextLevelName = null;
        if (learning.NEXT_LEARNING) {
          const nextLevel = await models.Level.findOne({
            where: { ID_LEVEL: learning.NEXT_LEARNING },
          });
          if (nextLevel) {
            nextLevelName = nextLevel.NAME_LEVEL;
          }
        }

        return {
          SCORE: learning.SCORE,
          CURRENT_LEVEL: learning.level?.NAME_LEVEL || "No level",
          NEXT_LEVEL: nextLevelName,
          STUDENT_FINISH: learning.STUDENT_FINISH,
          TOPIC_NAME: learning.level?.levelTopic?.NAME_TOPIC || "No topic",
          SECTION_NAME:
            learning.level?.levelTopic?.topicSection?.NAME_SECTION ||
            "No section",
          IS_PASS: learning.IS_PASS,
        };
      })
    );

    const paginatedLearnings = formattedLearnings.slice(
      (page - 1) * limit,
      page * limit
    );

    const totalPages = Math.ceil(formattedLearnings.length / limit);
    const currentPage = parseInt(page);

    response(
      200,
      {
        history: paginatedLearnings,
        currentPage,
        totalPages,
        totalItems: formattedLearnings.length,
      },
      "Learning history retrieved successfully",
      res
    );
  } catch (error) {
    console.error(error);
    response(500, null, "Internal Server Error", res);
  }
};

export const learningHistoryBySectionId = async (req, res) => {
  const { page = 1, limit = 10 } = req.query;

  try {
    if (!req.user) {
      return response(401, null, "User not authenticated", res);
    }

    const { ID } = req.user;
    const { sectionId } = req.params;

    const stdLearnings = await models.StdLearning.findAll({
      where: {
        ID,
        STUDENT_FINISH: {
          [models.Sequelize.Op.ne]: null,
        },
        SCORE: {
          [models.Sequelize.Op.ne]: null,
        },
        NEXT_LEARNING: {
          [models.Sequelize.Op.ne]: null,
        },
      },
      include: [
        {
          model: models.Level,
          as: "level",
          include: [
            {
              model: models.Topic,
              as: "levelTopic",
              include: [
                {
                  model: models.Section,
                  as: "topicSection",
                  where: { ID_SECTION: sectionId },
                  required: true,
                },
              ],
              required: true,
            },
          ],
          required: true,
        },
      ],
      order: [["STUDENT_FINISH", "DESC"]],
    });

    if (!stdLearnings.length) {
      return response(
        404,
        null,
        "No learning history found for the specified section",
        res
      );
    }

    const formattedLearnings = await Promise.all(
      stdLearnings.map(async (learning) => {
        let nextLevelName = null;
        if (learning.NEXT_LEARNING) {
          const nextLevel = await models.Level.findOne({
            where: { ID_LEVEL: learning.NEXT_LEARNING },
          });
          if (nextLevel) {
            nextLevelName = nextLevel.NAME_LEVEL;
          }
        }

        return {
          SCORE: learning.SCORE,
          CURRENT_LEVEL: learning.level?.NAME_LEVEL || "No level",
          NEXT_LEVEL: nextLevelName,
          STUDENT_FINISH: learning.STUDENT_FINISH,
          TOPIC_NAME: learning.level?.levelTopic?.NAME_TOPIC || "No topic",
          SECTION_NAME:
            learning.level?.levelTopic?.topicSection?.NAME_SECTION ||
            "No section",
          IS_PASS: learning.IS_PASS,
        };
      })
    );

    const paginatedLearnings = formattedLearnings.slice(
      (page - 1) * limit,
      page * limit
    );

    const totalPages = Math.ceil(formattedLearnings.length / limit);
    const currentPage = parseInt(page);

    response(
      200,
      {
        history: paginatedLearnings,
        currentPage,
        totalPages,
        totalItems: formattedLearnings.length,
      },
      "Learning history retrieved successfully",
      res
    );
  } catch (error) {
    console.log(error);
    response(500, null, "Internal Server Error", res);
  }
};

export const learningHistoryByTopicId = async (req, res) => {
  const { page = 1, limit = 10 } = req.query;

  try {
    if (!req.user) {
      return response(401, null, "User not authenticated", res);
    }

    const { ID } = req.user;
    const { topicId } = req.params;

    if (!topicId) {
      return response(400, null, "Topic ID is required", res);
    }

    const stdLearnings = await models.StdLearning.findAll({
      where: {
        ID,
        STUDENT_FINISH: {
          [models.Sequelize.Op.ne]: null,
        },
        SCORE: {
          [models.Sequelize.Op.ne]: null,
        },
        NEXT_LEARNING: {
          [models.Sequelize.Op.ne]: null,
        },
      },
      include: [
        {
          model: models.Level,
          as: "level",
          include: [
            {
              model: models.Topic,
              as: "levelTopic",
              where: { ID_TOPIC: topicId },
              required: true,
              include: [
                {
                  model: models.Section,
                  as: "topicSection",
                  required: true,
                },
              ],
            },
          ],
          required: true,
        },
      ],
      order: [["STUDENT_FINISH", "DESC"]],
    });

    if (!stdLearnings.length) {
      return response(
        404,
        null,
        "No learning history found for the specified topic",
        res
      );
    }

    const formattedLearnings = await Promise.all(
      stdLearnings.map(async (learning) => {
        let nextLevelName = null;
        if (learning.NEXT_LEARNING) {
          const nextLevel = await models.Level.findOne({
            where: { ID_LEVEL: learning.NEXT_LEARNING },
          });
          if (nextLevel) {
            nextLevelName = nextLevel.NAME_LEVEL;
          }
        }

        return {
          SCORE: learning.SCORE,
          CURRENT_LEVEL: learning.level?.NAME_LEVEL || "No level",
          NEXT_LEVEL: nextLevelName,
          STUDENT_FINISH: learning.STUDENT_FINISH,
          TOPIC_NAME: learning.level?.levelTopic?.NAME_TOPIC || "No topic",
          SECTION_NAME:
            learning.level?.levelTopic?.topicSection?.NAME_SECTION ||
            "No section",
          IS_PASS: learning.IS_PASS,
        };
      })
    );

    const paginatedLearnings = formattedLearnings.slice(
      (page - 1) * limit,
      page * limit
    );

    const totalPages = Math.ceil(formattedLearnings.length / limit);
    const currentPage = parseInt(page);

    response(
      200,
      {
        history: paginatedLearnings,
        currentPage,
        totalPages,
        totalItems: formattedLearnings.length,
      },
      "Learning history retrieved successfully",
      res
    );
  } catch (error) {
    console.error(error);
    response(500, null, "Internal Server Error", res);
  }
};

export const recentStudentActivities = async (req, res) => {
  try {
    const stdLearnings = await models.StdLearning.findAll({
      where: {
        STUDENT_FINISH: {
          [models.Sequelize.Op.ne]: null,
        },
        SCORE: {
          [models.Sequelize.Op.ne]: null,
        },
        NEXT_LEARNING: {
          [models.Sequelize.Op.ne]: null,
        },
      },
      include: [
        {
          model: models.User,
          as: "learningUser",
          attributes: ["ID", "NAME_USERS"],
          include: [
            {
              model: models.Student,
              as: "students",
              attributes: ["NISN"],
            },
          ],
        },
        {
          model: models.Level,
          as: "level",
          attributes: ["NAME_LEVEL"],
          include: [
            {
              model: models.Topic,
              as: "levelTopic",
              attributes: ["NAME_TOPIC"],
              include: [
                {
                  model: models.Section,
                  as: "topicSection",
                  attributes: ["NAME_SECTION"],
                },
              ],
            },
          ],
        },
      ],
      order: [["STUDENT_FINISH", "DESC"]],
      limit: 5,
    });

    const recentActivities = stdLearnings.map((learning) => ({
      NISN: learning.learningUser?.students?.NISN || "N/A",
      NAME_USERS: learning.learningUser?.NAME_USERS || "N/A",
      NAME_SECTION:
        learning.level?.levelTopic?.topicSection?.NAME_SECTION || "N/A",
      NAME_TOPIC: learning.level?.levelTopic?.NAME_TOPIC || "N/A",
      NAME_LEVEL: learning.level?.NAME_LEVEL || "N/A",
      SCORE: learning.SCORE || "N/A",
    }));

    if (!recentActivities.length) {
      return res.status(404).json({ message: "No recent activities found" });
    }

    res.status(200).json({ recentActivities });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal Server Error" });
  }
};

export const getLastCreatedStdLearningByLevelId = async (req, res) => {
  try {
    if (!req.user) {
      return response(401, null, "User not authenticated", res);
    }

    const { ID } = req.user;
    const { levelId } = req.params;

    if (!levelId) {
      return response(400, null, "Level ID is required", res);
    }

    const latestStdLearning = await models.StdLearning.findOne({
      where: {
        ID: ID,
        ID_LEVEL: levelId,
      },
      order: [["STUDENT_START", "DESC"]],
    });

    if (!latestStdLearning) {
      return response(404, null, "No StdLearning data found", res);
    }

    response(200, latestStdLearning, "Success", res);
  } catch (error) {
    console.error(error);
    response(500, null, "Internal Server Error", res);
  }
};
