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

export const getSections = async (req, res) => {
  try {
    const sections = await models.Section.findAll({
      where: {
        IS_DELETED: 0,
      },
    });
    response(200, sections, "Success", res);
  } catch (error) {
    console.log(error);
    response(500, null, "Error retrieving sections data!", res);
  }
};

export const getSectionById = async (req, res) => {
  try {
    const { id } = req.params;
    const section = await models.Section.findByPk(id);

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

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

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

  try {
    const { count, rows: sections } = await models.Section.findAndCountAll({
      where: {
        IS_DELETED: 0,
        ...(search && {
          [models.Op.or]: [
            {
              NAME_SECTION: {
                [models.Op.like]: `%${search}%`,
              },
            },
            {
              DESCRIPTION_SECTION: {
                [models.Op.like]: `%${search}%`,
              },
            },
          ],
        }),
      },
      attributes: ["ID_SECTION", "NAME_SECTION", "DESCRIPTION_SECTION", "TIME_SECTION"],
      distinct: true,
    });

    const formattedSections = sections.map((section) => ({
      ID_SECTION: section.ID_SECTION,
      NAME_SECTION: section.NAME_SECTION,
      DESCRIPTION_SECTION: section.DESCRIPTION_SECTION,
      TIME_SECTION: section.TIME_SECTION,
    }));

    if (sort === "section") {
      formattedSections.sort((a, b) => a.NAME_SECTION.localeCompare(b.NAME_SECTION));
    } else if (sort === "description") {
      formattedSections.sort((a, b) => a.DESCRIPTION_SECTION.localeCompare(b.DESCRIPTION_SECTION));
    } else {
      formattedSections.sort(
        (a, b) => new Date(b.TIME_SECTION) - new Date(a.TIME_SECTION)
      );
    }

    const paginatedSections = formattedSections.slice(
      (page - 1) * limit,
      page * limit
    );

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

    response(
      200,
      {
        sections: paginatedSections,
        currentPage,
        totalPages,
        totalItems: count,
      },
      "Sections retrieved successfully",
      res
    );
  } catch (error) {
    console.log(error);
    response(500, null, "Error retrieving sections data!", res);
  }
};

export const createSection = async (req, res) => {
  const { NAME_SECTION, DESCRIPTION_SECTION } = req.body;
  const { THUMBNAIL } = req.filesToSave || {};

  if (!NAME_SECTION) {
    clearFileBuffers({ THUMBNAIL });
    return response(400, null, "Section name is required", res);
  }

  if (!DESCRIPTION_SECTION) {
    clearFileBuffers({ THUMBNAIL });
    return response(400, null, "Description is required", res);
  }

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

  try {
    const existingSection = await models.Section.findOne({
      where: { NAME_SECTION, IS_DELETED: 0 },
      transaction,
    });

    if (existingSection) {
      clearFileBuffers({ THUMBNAIL });
      await transaction.rollback();
      return response(409, null, "Section name already exists", res);
    }

    const newSection = await models.Section.create(
      {
        NAME_SECTION,
        DESCRIPTION_SECTION,
        THUMBNAIL: null,
      },
      { transaction }
    );

    const thumbnailFilename = THUMBNAIL
      ? saveFileToDisk(THUMBNAIL, "THUMBNAIL", newSection.ID_SECTION)
      : null;

    newSection.THUMBNAIL = thumbnailFilename;

    await newSection.save({ transaction });

    await transaction.commit();

    response(201, newSection, "Section created successfully", res);
  } catch (error) {
    console.log(error);

    await transaction.rollback();
    clearFileBuffers({ THUMBNAIL });

    response(500, null, "Internal Server Error", res);
  }
};

export const updateSectionById = async (req, res) => {
  const { id } = req.params;
  const { NAME_SECTION, DESCRIPTION_SECTION } = req.body;
  const { THUMBNAIL } = req.filesToSave || {};

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

  try {
    const section = await models.Section.findByPk(id, { transaction });

    if (!section) {
      clearFileBuffers({ THUMBNAIL });
      await transaction.rollback();
      return response(404, null, "Section not found", res);
    }

    if (NAME_SECTION && NAME_SECTION !== section.NAME_SECTION) {
      const existingSection = await models.Section.findOne({
        where: { NAME_SECTION },
        transaction,
      });

      if (existingSection) {
        clearFileBuffers({ THUMBNAIL });
        await transaction.rollback();
        return response(400, null, "Section name already exists", res);
      }

      section.NAME_SECTION = NAME_SECTION;
    }

    if (DESCRIPTION_SECTION) section.DESCRIPTION_SECTION = DESCRIPTION_SECTION;

    if (THUMBNAIL) {
      if (section.THUMBNAIL) {
        const oldThumbnailPath = path.join(
          "public/uploads/section",
          section.THUMBNAIL
        );
        if (fs.existsSync(oldThumbnailPath)) {
          fs.unlinkSync(oldThumbnailPath);
        }
      }

      section.THUMBNAIL = saveFileToDisk(
        THUMBNAIL,
        "THUMBNAIL",
        section.ID_SECTION
      );
    }

    await section.save({ transaction });

    await transaction.commit();

    response(200, section, "Section updated successfully", res);
  } catch (error) {
    console.log(error);

    await transaction.rollback();
    clearFileBuffers({ THUMBNAIL });

    response(500, null, "Internal Server Error", res);
  }
};

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

  try {
    const section = await models.Section.findByPk(id);

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

    section.IS_DELETED = 1;
    await section.save();

    await models.Topic.update({ IS_DELETED: 1 }, { where: { ID_SECTION: id } });

    await models.Level.update(
      { IS_DELETED: 1 },
      {
        where: {
          ID_TOPIC: {
            [models.Op.in]: models.Sequelize.literal(
              `(SELECT ID_TOPIC FROM topic WHERE ID_SECTION = '${id}')`
            ),
          },
        },
      }
    );

    await models.Exercise.update(
      { IS_DELETED: 1 },
      {
        where: {
          ID_LEVEL: {
            [models.Op.in]: models.Sequelize.literal(
              `(SELECT ID_LEVEL FROM level WHERE ID_TOPIC IN (SELECT ID_TOPIC FROM topic WHERE ID_SECTION = '${id}') )`
            ),
          },
        },
      }
    );

    response(
      200,
      null,
      "Section, topics, levels, and related exercises soft deleted successfully",
      res
    );
  } catch (error) {
    console.log(error);
    response(500, null, "Internal Server Error", res);
  }
};
