import response from "../../response.js";
import models from "../../models/index.js";
import {
  clearFileBuffers,
  saveFileToDisk,
} from "../../middlewares/uploadExercise.js";
import fs from "fs";
import path from "path";

export const createMultipleChoicesExercise = async (req, res) => {
  const {
    ID_LEVEL,
    TITLE,
    QUESTION,
    OPTION_A,
    OPTION_B,
    OPTION_C,
    OPTION_D,
    OPTION_E,
    ANSWER_KEY,
    SCORE_WEIGHT,
    VIDEO,
  } = req.body;

  const { IMAGE, AUDIO } = req.filesToSave || {};

  if (!ID_LEVEL) return response(400, null, "Level ID is required", res);
  if (!QUESTION) return response(400, null, "Question is required", res);
  if (!OPTION_A) return response(400, null, "Option A is required", res);
  if (!OPTION_B) return response(400, null, "Option B is required", res);
  if (!OPTION_C) return response(400, null, "Option C is required", res);
  if (!OPTION_D) return response(400, null, "Option D is required", res);
  if (!OPTION_E) return response(400, null, "Option E is required", res);
  if (!ANSWER_KEY) return response(400, null, "Answer key is required", res);
  if (!SCORE_WEIGHT)
    return response(400, null, "Score weight is required", res);

  const transaction = await models.db.transaction();

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

    let generatedTitle = TITLE;

    if (!TITLE) {
      const lastExercise = await models.Exercise.findOne({
        where: { ID_LEVEL },
        order: [["TITLE", "DESC"]],
        limit: 1,
      });

      if (lastExercise && lastExercise.TITLE) {
        const lastTitleNumber = parseInt(lastExercise.TITLE.split(" ")[1], 10);
        generatedTitle = `Soal ${lastTitleNumber + 1}`;
      } else {
        generatedTitle = `Soal 1`;
      }
    }

    const existingExercise = await models.Exercise.findOne({
      where: { ID_LEVEL, TITLE: generatedTitle },
    });
    if (existingExercise) {
      clearFileBuffers({ IMAGE, AUDIO });
      return response(
        400,
        null,
        "An exercise with the same title already exists in this level",
        res
      );
    }

    const newExercise = await models.Exercise.create(
      {
        ID_LEVEL,
        TITLE: generatedTitle,
        QUESTION,
        SCORE_WEIGHT,
        QUESTION_TYPE: "MCQ",
        AUDIO: null,
        VIDEO: VIDEO || null,
        IMAGE: null,
      },
      { transaction }
    );

    const audioFilename = AUDIO
      ? saveFileToDisk(AUDIO, "AUDIO", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
      : null;
    const imageFilename = IMAGE
      ? saveFileToDisk(IMAGE, "IMAGE", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
      : null;

    newExercise.AUDIO = audioFilename;
    newExercise.IMAGE = imageFilename;
    await newExercise.save({ transaction });

    const newMultipleChoices = await models.MultipleChoices.create(
      {
        ID_ADMIN_EXERCISE: newExercise.ID_ADMIN_EXERCISE,
        OPTION_A,
        OPTION_B,
        OPTION_C,
        OPTION_D,
        OPTION_E,
        ANSWER_KEY,
      },
      { transaction }
    );

    await transaction.commit();

    const payload = {
      exercise: newExercise,
      multipleChoices: newMultipleChoices,
    };

    response(201, payload, "Exercise created successfully", res);
  } catch (error) {
    console.error(error);
    await transaction.rollback();
    clearFileBuffers({ IMAGE, AUDIO });
    response(500, null, "Internal Server Error", res);
  }
};

export const updateMultipleChoicesExerciseById = async (req, res) => {
  const { id } = req.params;
  const {
    ID_LEVEL,
    QUESTION,
    OPTION_A,
    OPTION_B,
    OPTION_C,
    OPTION_D,
    OPTION_E,
    ANSWER_KEY,
    SCORE_WEIGHT,
    VIDEO,
  } = req.body;

  const { IMAGE, AUDIO } = req.filesToSave || {};

  const transaction = await models.db.transaction();

  try {
    const exercise = await models.Exercise.findByPk(id, { transaction });

    if (!exercise) {
      clearFileBuffers({ IMAGE, AUDIO });
      await transaction.rollback();
      return response(404, null, "Exercise not found", res);
    }

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

    if (QUESTION) exercise.QUESTION = QUESTION;
    if (SCORE_WEIGHT) exercise.SCORE_WEIGHT = SCORE_WEIGHT;
    if (VIDEO) exercise.VIDEO = VIDEO;

    if (AUDIO) {
      if (exercise.AUDIO) {
        const oldAudioPath = path.join(
          "public/uploads/exercise/audio",
          exercise.AUDIO
        );
        if (fs.existsSync(oldAudioPath)) {
          fs.unlinkSync(oldAudioPath);
        }
      }
      exercise.AUDIO = saveFileToDisk(
        AUDIO,
        "AUDIO",
        ID_LEVEL || exercise.ID_LEVEL,
        exercise.ID_ADMIN_EXERCISE
      );
    }

    if (IMAGE) {
      if (exercise.IMAGE) {
        const oldImagePath = path.join(
          "public/uploads/exercise/image",
          exercise.IMAGE
        );
        if (fs.existsSync(oldImagePath)) {
          fs.unlinkSync(oldImagePath);
        }
      }
      exercise.IMAGE = saveFileToDisk(
        IMAGE,
        "IMAGE",
        ID_LEVEL || exercise.ID_LEVEL,
        exercise.ID_ADMIN_EXERCISE
      );
    }

    await exercise.save({ transaction });

    const multipleChoices = await models.MultipleChoices.findOne({
      where: { ID_ADMIN_EXERCISE: exercise.ID_ADMIN_EXERCISE },
      transaction,
    });

    if (!multipleChoices) {
      clearFileBuffers({ IMAGE, AUDIO });
      await transaction.rollback();
      return response(404, null, "Multiple Choices not found", res);
    }

    if (OPTION_A) multipleChoices.OPTION_A = OPTION_A;
    if (OPTION_B) multipleChoices.OPTION_B = OPTION_B;
    if (OPTION_C) multipleChoices.OPTION_C = OPTION_C;
    if (OPTION_D) multipleChoices.OPTION_D = OPTION_D;
    if (OPTION_E) multipleChoices.OPTION_E = OPTION_E;
    if (ANSWER_KEY) multipleChoices.ANSWER_KEY = ANSWER_KEY;

    await multipleChoices.save({ transaction });

    await transaction.commit();

    const payload = {
      exercise,
      multipleChoices,
    };

    response(200, payload, "Exercise updated successfully", res);
  } catch (error) {
    console.log(error);
    clearFileBuffers({ IMAGE, AUDIO });
    await transaction.rollback();
    response(500, null, "Internal Server Error", res);
  }
};
