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

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

export const getMonitoringById = async (req, res) => {
  try {
    const { id } = req.params;
    const monitoring = await models.Monitoring.findByPk(id);

    if (!monitoring) {
      return response(404, null, "Monitoring data not found", res);
    }

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

export const createMonitoring = async (req) => {
  const { ID_STUDENT_LEARNING } = req.body;

  if (!req.user) {
    throw new Error("User not authenticated");
  }

  if (!ID_STUDENT_LEARNING) {
    throw new Error("Student Learning ID is required");
  }

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

    if (existingMonitoring) {
      return existingMonitoring.toJSON();
    }

    const stdLearning = await models.StdLearning.findByPk(ID_STUDENT_LEARNING);

    if (!stdLearning) {
      throw new Error("Student learning data not found");
    }

    const userID = stdLearning.ID;

    const student = await models.Student.findOne({ where: { ID: userID } });

    if (!student) {
      throw new Error("Student data not found");
    }

    const { ID_SISWA } = student;

    const studentClass = await models.Student.findOne({
      where: { ID_SISWA: ID_SISWA },
      attributes: ["ID_CLASS"],
    });

    const ID_CLASS =
      studentClass && studentClass.ID_CLASS ? studentClass.ID_CLASS : null;

    const newMonitoring = await models.Monitoring.create({
      ID_STUDENT_LEARNING,
      ID_CLASS,
    });

    return newMonitoring.toJSON();
  } catch (error) {
    console.error(error);
    throw new Error("Internal Server Error");
  }
};

export const updateMonitoringClass = async ({
  ID_STUDENT_LEARNING,
  ID_CLASS,
}) => {
  if (!ID_STUDENT_LEARNING || !ID_CLASS) {
    throw new Error("Student Learning ID and Class ID are required");
  }

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

    if (!monitoring) {
      throw new Error("Monitoring data not found");
    }

    monitoring.ID_CLASS = ID_CLASS;
    await monitoring.save();

    return monitoring;
  } catch (error) {
    console.error(error);
    throw error;
  }
};

export const monitoringStudentsProgress = async (req, res) => {
  const { page = 1, limit = 10, search = "", sort = "time" } = req.query;

  try {
    const { count, rows: monitorings } =
      await models.Monitoring.findAndCountAll({
        include: [
          {
            model: models.StdLearning,
            as: "stdLearningMonitoring",
            include: [
              {
                model: models.User,
                as: "learningUser",
                attributes: ["NAME_USERS"],
                include: [
                  {
                    model: models.Student,
                    as: "students",
                    attributes: ["NISN"],
                    include: [
                      {
                        model: models.Class,
                        as: "studentClass",
                        attributes: ["NAME_CLASS"],
                      },
                    ],
                  },
                ],
              },
              {
                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"],
                      },
                    ],
                  },
                ],
              },
            ],
          },
        ],
        where: {
          ...(search && {
            [models.Op.or]: [
              {
                "$stdLearningMonitoring.learningUser.students.NISN$": {
                  [models.Op.like]: `%${search}%`,
                },
              },
              {
                "$stdLearningMonitoring.learningUser.NAME_USERS$": {
                  [models.Op.like]: `%${search}%`,
                },
              },
              {
                "$stdLearningMonitoring.level.levelTopic.topicSection.NAME_SECTION$":
                  {
                    [models.Op.like]: `%${search}%`,
                  },
              },
              {
                "$stdLearningMonitoring.level.levelTopic.NAME_TOPIC$": {
                  [models.Op.like]: `%${search}%`,
                },
              },
            ],
          }),
        },
        distinct: true,
      });

    const formattedResult = monitorings.map((monitoring) => ({
      ID_MONITORING: monitoring.ID_MONITORING,
      NISN: monitoring.stdLearningMonitoring?.learningUser?.students?.NISN,
      NAME_USERS: monitoring.stdLearningMonitoring?.learningUser?.NAME_USERS,
      NAME_SECTION:
        monitoring.stdLearningMonitoring?.level?.levelTopic?.topicSection
          ?.NAME_SECTION,
      NAME_TOPIC:
        monitoring.stdLearningMonitoring?.level?.levelTopic?.NAME_TOPIC,
      NAME_CLASS:
        monitoring.stdLearningMonitoring?.learningUser?.students?.studentClass
          ?.NAME_CLASS ?? null,
    }));

    if (sort === "nisn") {
      formattedResult.sort((a, b) => a.NISN.localeCompare(b.NISN));
    } else if (sort === "name") {
      formattedResult.sort((a, b) => a.NAME_USERS.localeCompare(b.NAME_USERS));
    } else if (sort === "section") {
      formattedResult.sort((a, b) =>
        a.NAME_SECTION.localeCompare(b.NAME_SECTION)
      );
    } else if (sort === "topic") {
      formattedResult.sort((a, b) => a.NAME_TOPIC.localeCompare(b.NAME_TOPIC));
    } else {
      formattedResult.sort((a, b) => new Date(b.TIME) - new Date(a.TIME));
    }

    const paginatedResult = formattedResult.slice(
      (page - 1) * limit,
      page * limit
    );
    const totalPages = Math.ceil(count / limit);
    const currentPage = parseInt(page);

    response(
      200,
      {
        monitorings: paginatedResult,
        currentPage,
        totalPages,
        totalItems: count,
      },
      "Success retrieving student monitoring progress!",
      res
    );
  } catch (error) {
    console.error(error);
    response(500, null, "Error retrieving student monitoring progress!", res);
  }
};

export const monitoringStudentProgressById = async (req, res) => {
  const { id } = req.params;
  const { page = 1, limit = 10, search = "", sort = "start" } = req.query;

  try {
    const monitoring = await models.Monitoring.findOne({
      where: { ID_MONITORING: id },
      include: [
        {
          model: models.StdLearning,
          as: "stdLearningMonitoring",
          attributes: [
            "ID",
            "ID_LEVEL",
            "SCORE",
            "FEEDBACK_STUDENT",
            "STUDENT_START",
            "STUDENT_FINISH",
            "ID_STUDENT_LEARNING",
          ],
          include: [
            {
              model: models.Level,
              as: "level",
              attributes: ["ID_TOPIC", "NAME_LEVEL"],
              include: [
                {
                  model: models.Topic,
                  as: "levelTopic",
                  attributes: ["NAME_TOPIC"],
                  include: [
                    {
                      model: models.Section,
                      as: "topicSection",
                      attributes: ["NAME_SECTION"],
                    },
                  ],
                },
              ],
            },
            {
              model: models.User,
              as: "learningUser",
              attributes: ["NAME_USERS"],
              include: [
                {
                  model: models.Student,
                  as: "students",
                  attributes: ["NISN"],
                },
              ],
            },
          ],
        },
      ],
    });

    if (!monitoring) {
      return response(404, null, "Monitoring data not found!", res);
    }

    const stdLearning = monitoring.stdLearningMonitoring;

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

    const userID = stdLearning.ID;
    const topicID = stdLearning.level.ID_TOPIC;
    const studentName = stdLearning.learningUser.NAME_USERS;
    const nisn = stdLearning.learningUser.students.NISN;
    const topicName = stdLearning.level.levelTopic.NAME_TOPIC;
    const sectionName = stdLearning.level.levelTopic.topicSection.NAME_SECTION;

    // Fetch levels with pagination, search, and sort
    const levels = await models.StdLearning.findAndCountAll({
      where: {
        ID: userID,
        ...(search && {
          [models.Op.or]: [
            {
              "$level.NAME_LEVEL$": { [models.Op.like]: `%${search}%` },
            },
            {
              SCORE: { [models.Op.like]: `%${search}%` },
            },
            {
              FEEDBACK_STUDENT: { [models.Op.like]: `%${search}%` },
            },
            // {
            //   [models.Sequelize.fn('DATE_FORMAT', models.Sequelize.col('STUDENT_START'), '%Y-%m-%d')]: {
            //     [models.Op.like]: `%${search}%`,
            //   },
            // },
            // {
            //   [models.Sequelize.fn('DATE_FORMAT', models.Sequelize.col('STUDENT_FINISH'), '%Y-%m-%d')]: {
            //     [models.Op.like]: `%${search}%`,
            //   },
            // },
          ],
        }),
      },
      include: [
        {
          model: models.Level,
          as: "level",
          attributes: ["NAME_LEVEL", "ID_TOPIC"],
          where: {
            ID_TOPIC: topicID,
          },
        },
      ],
      attributes: [
        "SCORE",
        "FEEDBACK_STUDENT",
        "STUDENT_START",
        "STUDENT_FINISH",
      ],
      distinct: true,
    });

    const levelArray = levels.rows
      .map((learning) => ({
        NAME_LEVEL: learning.level.NAME_LEVEL,
        SCORE: learning.SCORE,
        FEEDBACK_STUDENT: learning.FEEDBACK_STUDENT,
        STUDENT_START: learning.STUDENT_START,
        STUDENT_FINISH: learning.STUDENT_FINISH,
      }))
      .sort((a, b) => {
        if (sort === "level") {
          return a.NAME_LEVEL.localeCompare(b.NAME_LEVEL);
        } else if (sort === "score") {
          return b.SCORE - a.SCORE;
        } else if (sort === "feedback") {
          return a.FEEDBACK_STUDENT.localeCompare(b.FEEDBACK_STUDENT);
        } else if (sort === "start") {
          return new Date(a.STUDENT_START) - new Date(b.STUDENT_START);
        } else if (sort === "finish") {
          return new Date(a.STUDENT_FINISH) - new Date(b.STUDENT_FINISH);
        }
        return 0;
      });

    // Pagination logic
    const paginatedResult = levelArray.slice((page - 1) * limit, page * limit);
    const totalPages = Math.ceil(levels.count / limit);
    const currentPage = parseInt(page);

    const result = {
      ID_MONITORING: monitoring.ID_MONITORING,
      NAME_SECTION: sectionName,
      NAME_TOPIC: topicName,
      NAME_USERS: studentName,
      NISN: nisn,
      levels: paginatedResult,
      currentPage,
      totalPages,
      totalItems: levels.count,
    };

    response(200, result, "Success retrieving student progress!", res);
  } catch (error) {
    console.error(error);
    response(500, null, "Error retrieving student progress!", res);
  }
};

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

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

  const { ID } = req.user;

  if (!ID) {
    return response(401, null, "Unauthorized: User ID not provided", res);
  }

  try {
    const teacher = await models.Teacher.findOne({
      where: { ID: ID },
      attributes: ["ID_GURU"],
    });

    if (!teacher) {
      return response(404, null, "Teacher not found!", res);
    }

    const [updatedRows] = await models.Monitoring.update(
      {
        ID_GURU: teacher.ID_GURU,
        FEEDBACK_GURU: feedback,
      },
      {
        where: { ID_MONITORING: id },
        returning: true,
      }
    );

    if (updatedRows === 0) {
      return response(404, null, "Monitoring data not found!", res);
    }

    const monitoringWithRelations = await models.Monitoring.findOne({
      where: { ID_MONITORING: id },
      include: [
        {
          model: models.Teacher,
          as: "monitoringTeacher",
          attributes: ["ID_GURU"],
          include: [
            {
              model: models.User,
              as: "teacherUser",
              attributes: ["NAME_USERS"],
            },
          ],
        },
      ],
    });

    if (!monitoringWithRelations) {
      return response(404, null, "Updated monitoring data not found!", res);
    }

    const result = {
      ID_MONITORING: monitoringWithRelations.ID_MONITORING,
      FEEDBACK_GURU: monitoringWithRelations.FEEDBACK_GURU,
      ID_GURU: monitoringWithRelations.monitoringTeacher?.ID_GURU,
      TEACHER_NAME:
        monitoringWithRelations.monitoringTeacher?.teacherUser?.NAME_USERS,
    };

    response(200, result, "Success updating teacher feedback!", res);
  } catch (error) {
    console.error("Error in monitoringFeedback:", error);
    response(500, null, "Error updating teacher feedback!", res);
  }
};

export const getMonitoringByTopicId = async (req, res) => {
  const { topicId } = req.params;

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

  const { ID } = req.user;

  if (!ID) {
    return response(401, null, "Unauthorized: User ID not provided", res);
  }

  try {
    const stdLearning = await models.StdLearning.findOne({
      where: {
        ID: ID,
      },
      include: [
        {
          model: models.Level,
          as: "level",
          where: { ID_TOPIC: topicId },
          attributes: ["ID_LEVEL", "NAME_LEVEL"],
          include: [
            {
              model: models.Topic,
              as: "levelTopic",
              attributes: ["NAME_TOPIC"],
            },
          ],
        },
      ],
    });

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

    const monitoringData = await models.Monitoring.findOne({
      where: {
        ID_STUDENT_LEARNING: stdLearning.ID_STUDENT_LEARNING,
      },
      include: [
        {
          model: models.Teacher,
          as: "monitoringTeacher",
          attributes: ["ID_GURU"],
          include: [
            {
              model: models.User,
              as: "teacherUser",
              attributes: ["NAME_USERS"],
            },
          ],
        },
      ],
    });

    if (!monitoringData) {
      return response(
        404,
        null,
        "Monitoring data not found for this learning record!",
        res
      );
    }

    const result = {
      ID_MONITORING: monitoringData.ID_MONITORING,
      NAME_TOPIC: stdLearning.level?.levelTopic?.NAME_TOPIC,
      NAME_LEVEL: stdLearning.level?.NAME_LEVEL,
      TEACHER_NAME: monitoringData.monitoringTeacher?.teacherUser?.NAME_USERS,
      FEEDBACK_GURU: monitoringData.FEEDBACK_GURU,
      TIME_MONITORING: monitoringData.TIME_MONITORING,
    };

    response(200, result, "Success retrieving monitoring data!", res);
  } catch (error) {
    console.error("Error in getMonitoringByTopicId:", error);
    response(500, null, "Error retrieving monitoring data!", res);
  }
};
