const { Op, where } = require("sequelize");
const dbSAPPS = require("../../helpers/db");
require("dotenv").config();

const path = require("path");
const fs = require("fs");

module.exports = {
  getAll,
  filterOwnerOrParticipant,
  filter,
  option,
  count,
  create,
  update,
  enabled,
  delete: _delete,
};

async function getAll() {
  try {
    const moms = await dbSAPPS.Mom.findAll({
      order: [["modified", "DESC"]],
      include: [
        {
          model: dbSAPPS.MomParticipant,
          as: "momparticipants",
          attributes: ["employee_id"],
          include: [
            {
              model: dbSAPPS.Employee,
              as: "employee",
              attributes: ["id", "employee_name", "user_id", "department_id"],
              include: [{ model: dbSAPPS.Department, as: "department", attributes: ["id", "display_name"] }],
            },
          ],
        },
        {
          model: dbSAPPS.MomAgenda,
          as: "momagendas",
          attributes: ["id", "agenda"],
        },
        {
          model: dbSAPPS.MomResult,
          as: "momresults",
          attributes: ["id", "result"],
        },
        {
          model: dbSAPPS.MomFile,
          as: "momfiles",
          attributes: ["id", "filename", "path", "size"],
        },
      ],
    });

    return {
      moms,
      success: true,
      message: "Mom loaded successfully!",
    };
  } catch (error) {
    const errorMessage = error.message || "Failed to load Specialist!";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function filterOwnerOrParticipant(params) {
  try {
    const filterConditions = {
      [Op.or]: [
        { owner: params.user_id },
        {
          id: {
            [Op.in]: (
              await dbSAPPS.MomParticipant.findAll({
                attributes: ["mom_id"],
                where: {
                  employee_id: (
                    await dbSAPPS.Employee.findOne({
                      attributes: ["id"],
                      where: {
                        user_id: params.user_id,
                      },
                    })
                  ).id,
                },
              })
            ).map((mp) => mp.mom_id),
          },
        },
      ],
    };

    const moms = await dbSAPPS.Mom.findAll({
      order: [["modified", "DESC"]],
      where: filterConditions,
      include: [
        {
          model: dbSAPPS.MomParticipant,
          as: "momparticipants",
          attributes: ["employee_id"],
          include: [
            {
              model: dbSAPPS.Employee,
              as: "employee",
              attributes: ["id", "employee_name", "user_id", "department_id"],
              include: [{ model: dbSAPPS.Department, as: "department", attributes: ["id", "display_name"] }],
            },
          ],
        },
        {
          model: dbSAPPS.MomAgenda,
          as: "momagendas",
          attributes: ["id", "agenda"],
        },
        // {
        //     model: dbSAPPS.MomResult,
        //     as: 'momresults',
        //     attributes: ['id', 'result'],
        // },
        {
          model: dbSAPPS.MomFile,
          as: "momfiles",
          attributes: ["id", "filename", "path", "size"],
        },
      ],
    });

    const data = await Promise.all(
      moms.map(async (mom) => {
        const ownerData = await dbSAPPS.User.findOne({
          where: { id: mom.owner },
          attributes: ["id"],
          include: [
            {
              model: dbSAPPS.Employee,
              as: "employee",
              attributes: ["id", "employee_name", "user_id"],
              include: [{ model: dbSAPPS.Designation, as: "designation", attributes: ["id", "display_name"] }],
            },
          ],
        });

        return {
          ...mom.dataValues,
          ownerData,
        };
      })
    );

    return {
      success: true,
      moms: data,
      message: "moms loaded successfully!",
    };
  } catch (error) {
    console.error("Error retrieving moms: ", error);
    const errorMessage = error.message || "Failed to retrieve moms. Please try again later.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function filter(params) {
  const filterConditions = {};

  if (params.meeting_name) {
    filterConditions.meeting_name = {
      [Op.like]: `%${params.meeting_name}%`,
    };
  }

  if (params.enabled) {
    filterConditions.enabled = {
      [Op.eq]: params.enabled === "1" ? true : false,
    };
  }

  try {
    const moms = await dbSAPPS.Mom.findAll({
      where: filterConditions,
      order: [["modified", "DESC"]],
      include: [
        {
          model: dbSAPPS.MomParticipant,
          as: "momparticipants",
          attributes: ["employee_id"],
          include: [
            {
              model: dbSAPPS.Employee,
              as: "employee",
              attributes: ["id", "employee_name", "user_id", "department_id"],
              include: [{ model: dbSAPPS.Department, as: "department", attributes: ["id", "display_name"] }],
            },
          ],
        },
        {
          model: dbSAPPS.MomAgenda,
          as: "momagendas",
          attributes: ["id", "agenda"],
        },
        // {
        //     model: dbSAPPS.MomResult,
        //     as: 'momresults',
        //     attributes: ['id', 'result'],
        // }
        {
          model: dbSAPPS.MomFile,
          as: "momfiles",
          attributes: ["id", "filename", "path", "size"],
        },
      ],
    });

    return {
      success: true,
      moms,
      message: "moms loaded successfully!",
    };
  } catch (error) {
    console.error("Error retrieving moms: ", error);
    const errorMessage = error.message || "Failed to retrieve moms. Please try again later.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function option() {
  try {
    const moms = await dbSAPPS.Mom.findAll({
      attributes: ["id", "display_name", "code"],
      where: { enabled: true },
      order: [["display_name", "ASC"]],
    });

    return {
      success: true,
      moms,
      message: "moms loaded successfully!",
    };
  } catch (error) {
    console.error("Error retrieving moms: ", error);
    const errorMessage = error.message || "Failed to retrieve moms. Please try again later.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function count() {
  try {
    const count = await dbSAPPS.Mom.count({
      where: { enabled: true },
    });

    return {
      success: true,
      count,
      message: "moms loaded successfully!",
    };
  } catch (error) {
    console.error("Error counting moms: ", error);
    return {
      success: false,
      message: "Failed to retrieve moms count. Please try again later.",
    };
  }
}

async function create(params) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    // Periksa apakah nama sudah ada di dalam database
    const existingMetting = await dbSAPPS.Mom.findOne({
      where: { meeting_name: params.meeting_name, meeting_date: params.meeting_date },
    });
    if (existingMetting) {
      return { success: false, message: `Meeting : "${params.meeting_name}" is already taken.` };
    }

    // Validasi apakah waktu sudah ada dalam rentang yang sesuai
    if (params.time_start > params.time_end) {
      return { success: false, message: "Time start cannot be greater than time end." };
    }

    if (params?.momparticipants?.length < 1) {
      return { success: false, message: "participants cannot be empty." };
    }

    // Jika tidak ada nilai untuk beberapa field, set default value
    if (!params.creation) params.creation = Date.now();
    if (!params.modified) params.modified = Date.now();
    if (!params.modified_by) params.modified_by = 1; // Default jika tidak ada nilai

    // Buat MOM baru
    const mom = await dbSAPPS.Mom.create(params, { transaction });

    // Cek dan proses jika ada momparticipants
    if (params.momparticipants) {
      // Pastikan `momparticipants` adalah array yang valid
      if (typeof params.momparticipants === "string") {
        try {
          params.momparticipants = JSON.parse(params.momparticipants);
        } catch (err) {
          return { success: false, message: "Invalid JSON format for participiants" };
        }
      }

      // Pastikan bahwa `momparticipants` adalah array yang valid dan memiliki data
      if (Array.isArray(params.momparticipants) && params.momparticipants.length > 0) {
        // Check unique data momparticipants
        const duplicates = params.momparticipants.reduce((acc, child, index, array) => {
          if (array.findIndex((item) => item.employee_id === child.employee_id) !== index) {
            acc.push(child.employee_id);
          }
          return acc;
        }, []);

        if (duplicates.length > 0) {
          await transaction.rollback();
          return {
            success: false,
            message: `Duplicate entries exist in participants for Employee: ${duplicates.join(
              ", "
            )}. Transaction rolled back.`,
          };
        }
        // Persiapkan data anak untuk disimpan
        const participants = params.momparticipants.map((participant) => ({
          ...participant,
          creation: Date.now(),
          modified: Date.now(),
          modified_by: params.modified_by || 1,
          owner: params.owner || 1,
          mom_id: mom.id, // Assign ID dari MOM yang baru saja dibuat
        }));

        // Insert data anak menggunakan bulkCreate
        await dbSAPPS.MomParticipant.bulkCreate(participants, { transaction });
      }
    }

    if (params.momagendas) {
      // Pastikan `momparticipants` adalah array yang valid
      if (typeof params.momagendas === "string") {
        try {
          params.momagendas = JSON.parse(params.momagendas);
        } catch (err) {
          return { success: false, message: "Invalid JSON format for agenda" };
        }
      }

      // Pastikan bahwa `momagendas` adalah array yang valid dan memiliki data
      if (Array.isArray(params.momagendas) && params.momagendas.length > 0) {
        // Persiapkan data anak untuk disimpan
        const agendas = params.momagendas.map((agenda) => ({
          ...agenda,
          creation: Date.now(),
          modified: Date.now(),
          modified_by: params.modified_by || 1,
          owner: params.owner || 1,
          mom_id: mom.id, // Assign ID dari MOM yang baru saja dibuat
        }));

        // Insert data anak menggunakan bulkCreate
        await dbSAPPS.MomAgenda.bulkCreate(agendas, { transaction });
      }
    }

    if (params.filesData) {
      // Persiapkan data anak untuk disimpan
      const files = params.filesData.map((file) => ({
        ...file,
        creation: Date.now(),
        modified: Date.now(),
        modified_by: params.modified_by || 1,
        owner: params.owner || 1,
        mom_id: mom.id, // Assign ID dari MOM yang baru saja dibuat
      }));

      // Insert data anak menggunakan bulkCreate
      await dbSAPPS.MomFile.bulkCreate(files, { transaction });
    }

    // Commit transaksi jika semua berhasil
    await transaction.commit();
    return {
      success: true,
      message: "MOM has been created!",
    };
  } catch (error) {
    // Rollback transaksi jika ada error
    await transaction.rollback();
    const errorMessage = error.message || "An error occurred during creating mom.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

// async function update(params) {
//     const transaction = await dbSAPPS.sequelize.transaction();
//     try {
//         // 1. Periksa apakah MOM yang akan diupdate ada
//         const existingMom = await dbSAPPS.Mom.findByPk(params.id, { transaction });
//         if (!existingMom) {
//             await transaction.rollback();
//             return { success: false, message: "MOM not found." };
//         }

//         // 2. Validasi nama meeting jika diubah
//         if (params.meeting_name && params.meeting_name !== existingMom.meeting_name) {
//             const duplicateMeeting = await dbSAPPS.Mom.findOne({
//                 where: { meeting_name: params.meeting_name },
//                 transaction
//             });
//             if (duplicateMeeting && duplicateMeeting.id !== params.id) {
//                 await transaction.rollback();
//                 return { success: false, message: `Meeting : "${params.meeting_name}" is already taken by another MOM.` };
//             }
//         }

//         // 3. Validasi rentang waktu
//         if (params.time_start && params.time_end) {
//             if (params.time_start > params.time_end) {
//                 await transaction.rollback();
//                 return { success: false, message: "Time start cannot be greater than time end." };
//             }
//         } else if (params.time_start && !params.time_end) {
//             if (params.time_start > existingMom.time_end) {
//                 await transaction.rollback();
//                 return { success: false, message: "Time start cannot be greater than existing time end." };
//             }
//         } else if (!params.time_start && params.time_end) {
//             if (existingMom.time_start > params.time_end) {
//                 await transaction.rollback();
//                 return { success: false, message: "Existing time start cannot be greater than new time end." };
//             }
//         }

//         // 4. Set nilai default untuk modified dan modified_by
//         params.modified = Date.now();
//         if (!params.modified_by) params.modified_by = 1; // Default jika tidak ada nilai

//         // 5. Update data MOM utama
//         await existingMom.update(params, { transaction });

//         // 6. Cek dan proses momparticipants
//         if (params.momparticipants) {
//             // Pastikan `momparticipants` adalah array yang valid
//             if (typeof params.momparticipants === 'string') {
//                 try {
//                     params.momparticipants = JSON.parse(params.momparticipants);
//                 } catch (err) {
//                     await transaction.rollback();
//                     return { success: false, message: 'Invalid JSON format for participants.' };
//                 }
//             }

//             if (!Array.isArray(params.momparticipants) || params.momparticipants.length < 1) {
//                 await transaction.rollback();
//                 return { success: false, message: "Participants cannot be empty." };
//             }

//             // Check unique data momparticipants
//             const duplicates = params.momparticipants.reduce((acc, child, index, array) => {
//                 if (array.findIndex(item => item.employee_id === child.employee_id) !== index) {
//                     acc.push(child.employee_id);
//                 }
//                 return acc;
//             }, []);

//             if (duplicates.length > 0) {
//                 await transaction.rollback();
//                 return {
//                     success: false,
//                     message: `Duplicate entries exist in participants for Employee: ${duplicates.join(', ')}. Transaction rolled back.`
//                 };
//             }

//             // Hapus peserta yang sudah ada untuk MOM ini
//             await dbSAPPS.MomParticipant.destroy({
//                 where: { mom_id: existingMom.id },
//                 transaction
//             });

//             // Persiapkan data peserta baru untuk disimpan
//             const participants = params.momparticipants.map(participant => ({
//                 ...participant,
//                 creation: Date.now(),
//                 modified: Date.now(),
//                 modified_by: params.modified_by || 1,
//                 owner: params.owner || 1,
//                 mom_id: existingMom.id // Assign ID dari MOM yang diupdate
//             }));

//             // Insert data peserta baru menggunakan bulkCreate
//             await dbSAPPS.MomParticipant.bulkCreate(participants, { transaction });
//         }

//         // 7. Cek dan proses momagendas
//         if (params.momagendas) {
//             // Pastikan `momagendas` adalah array yang valid
//             if (typeof params.momagendas === 'string') {
//                 try {
//                     params.momagendas = JSON.parse(params.momagendas);
//                 } catch (err) {
//                     await transaction.rollback();
//                     return { success: false, message: 'Invalid JSON format for agenda.' };
//                 }
//             }

//             // Hapus agenda yang sudah ada untuk MOM ini
//             await dbSAPPS.MomAgenda.destroy({
//                 where: { mom_id: existingMom.id },
//                 transaction
//             });

//             // Pastikan bahwa `momagendas` adalah array yang valid dan memiliki data
//             if (Array.isArray(params.momagendas) && params.momagendas.length > 0) {
//                 // Persiapkan data agenda baru untuk disimpan
//                 const agendas = params.momagendas.map(agenda => ({
//                     ...agenda,
//                     creation: Date.now(),
//                     modified: Date.now(),
//                     modified_by: params.modified_by || 1,
//                     owner: params.owner || 1,
//                     mom_id: existingMom.id // Assign ID dari MOM yang diupdate
//                 }));

//                 // Insert data agenda baru menggunakan bulkCreate
//                 await dbSAPPS.MomAgenda.bulkCreate(agendas, { transaction });
//             }
//         }

//         // 8. Cek dan proses filesData
//         if (params.filesData) {
//             // Hapus file yang sudah ada untuk MOM ini
//             await dbSAPPS.MomFile.destroy({
//                 where: { mom_id: existingMom.id },
//                 transaction
//             });

//             // Persiapkan data file baru untuk disimpan
//             const files = params.filesData.map(file => ({
//                 ...file,
//                 creation: Date.now(),
//                 modified: Date.now(),
//                 modified_by: params.modified_by || 1,
//                 owner: params.owner || 1,
//                 mom_id: existingMom.id // Assign ID dari MOM yang diupdate
//             }));

//             // Insert data file baru menggunakan bulkCreate
//             await dbSAPPS.MomFile.bulkCreate(files, { transaction });
//         }

//         // Commit transaksi jika semua berhasil
//         await transaction.commit();
//         return {
//             success: true,
//             message: 'MOM has been updated successfully!'
//         };
//     } catch (error) {
//         // Rollback transaksi jika ada error
//         await transaction.rollback();
//         const errorMessage = error.message || 'An error occurred during updating MOM.';
//         return {
//             success: false,
//             message: errorMessage
//         };
//     }
// }

async function update(params) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    // 1. Periksa apakah MOM yang akan diupdate ada
    const existingMom = await dbSAPPS.Mom.findByPk(params.id, { transaction });
    if (!existingMom) {
      await transaction.rollback();
      return { success: false, message: "MOM not found." };
    }

    // 2. Validasi nama meeting jika diubah
    if (
      params.meeting_name &&
      params.meeting_name !== existingMom.meeting_name &&
      params.meeting_date !== existingMom.meeting_date
    ) {
      const duplicateMeeting = await dbSAPPS.Mom.findOne({
        where: { meeting_name: params.meeting_name, meeting_date: params.meeting_date },
        transaction,
      });
      if (duplicateMeeting && duplicateMeeting.id !== params.id) {
        await transaction.rollback();
        return { success: false, message: `Meeting : "${params.meeting_name}" is already taken by another MOM.` };
      }
    }

    // 3. Validasi rentang waktu
    if (params.time_start && params.time_end) {
      if (params.time_start > params.time_end) {
        await transaction.rollback();
        return { success: false, message: "Time start cannot be greater than time end." };
      }
    } else if (params.time_start && !params.time_end) {
      if (params.time_start > existingMom.time_end) {
        await transaction.rollback();
        return { success: false, message: "Time start cannot be greater than existing time end." };
      }
    } else if (!params.time_start && params.time_end) {
      if (existingMom.time_start > params.time_end) {
        await transaction.rollback();
        return { success: false, message: "Existing time start cannot be greater than new time end." };
      }
    }

    // 4. Set nilai default untuk modified dan modified_by
    params.modified = Date.now();
    if (!params.modified_by) params.modified_by = 1; // Default jika tidak ada nilai

    // 5. Update data MOM utama
    await existingMom.update(params, { transaction });

    // 6. Cek dan proses momparticipants
    if (params.momparticipants) {
      // Pastikan `momparticipants` adalah array yang valid
      if (typeof params.momparticipants === "string") {
        try {
          params.momparticipants = JSON.parse(params.momparticipants);
        } catch (err) {
          await transaction.rollback();
          return { success: false, message: "Invalid JSON format for participants." };
        }
      }

      if (!Array.isArray(params.momparticipants) || params.momparticipants.length < 1) {
        await transaction.rollback();
        return { success: false, message: "Participants cannot be empty." };
      }

      // Check unique data momparticipants
      const duplicates = params.momparticipants.reduce((acc, child, index, array) => {
        if (array.findIndex((item) => item.employee_id === child.employee_id) !== index) {
          acc.push(child.employee_id);
        }
        return acc;
      }, []);

      if (duplicates.length > 0) {
        await transaction.rollback();
        return {
          success: false,
          message: `Duplicate entries exist in participants for Employee: ${duplicates.join(
            ", "
          )}. Transaction rolled back.`,
        };
      }

      // Hapus peserta yang sudah ada untuk MOM ini
      await dbSAPPS.MomParticipant.destroy({
        where: { mom_id: existingMom.id },
        transaction,
      });

      // Persiapkan data peserta baru untuk disimpan
      const participants = params.momparticipants.map((participant) => ({
        ...participant,
        creation: Date.now(),
        modified: Date.now(),
        modified_by: params.modified_by || 1,
        owner: params.owner || 1,
        mom_id: existingMom.id, // Assign ID dari MOM yang diupdate
      }));

      // Insert data peserta baru menggunakan bulkCreate
      await dbSAPPS.MomParticipant.bulkCreate(participants, { transaction });
    }

    // 7. Cek dan proses momagendas
    if (params.momagendas) {
      // Pastikan `momagendas` adalah array yang valid
      if (typeof params.momagendas === "string") {
        try {
          params.momagendas = JSON.parse(params.momagendas);
        } catch (err) {
          await transaction.rollback();
          return { success: false, message: "Invalid JSON format for agenda." };
        }
      }

      // Hapus agenda yang sudah ada untuk MOM ini
      await dbSAPPS.MomAgenda.destroy({
        where: { mom_id: existingMom.id },
        transaction,
      });

      // Pastikan bahwa `momagendas` adalah array yang valid dan memiliki data
      if (Array.isArray(params.momagendas) && params.momagendas.length > 0) {
        // Persiapkan data agenda baru untuk disimpan
        const agendas = params.momagendas.map((agenda) => ({
          ...agenda,
          creation: Date.now(),
          modified: Date.now(),
          modified_by: params.modified_by || 1,
          owner: params.owner || 1,
          mom_id: existingMom.id, // Assign ID dari MOM yang diupdate
        }));

        // Insert data agenda baru menggunakan bulkCreate
        await dbSAPPS.MomAgenda.bulkCreate(agendas, { transaction });
      }
    }

    // 8. Cek dan proses filesData
    let existingFiles = [];
    if (params.existingFiles) {
      try {
        existingFiles =
          typeof params.existingFiles === "string" ? JSON.parse(params.existingFiles) : params.existingFiles;
      } catch (err) {
        await transaction.rollback();
        return { success: false, message: "Invalid JSON format for existingFiles." };
      }
    }

    const allFiles = [...existingFiles, ...(params.filesData || [])];

    if (allFiles.length > 0) {
      // Hapus semua yang lama dulu
      await dbSAPPS.MomFile.destroy({
        where: { mom_id: existingMom.id },
        transaction,
      });

      const files = allFiles.map((file) => ({
        ...file,
        creation: Date.now(),
        modified: Date.now(),
        modified_by: params.modified_by || 1,
        owner: params.owner || 1,
        mom_id: existingMom.id,
      }));

      await dbSAPPS.MomFile.bulkCreate(files, { transaction });
    }

    // Commit transaksi jika semua berhasil
    await transaction.commit();
    return {
      success: true,
      message: "MOM has been updated successfully!",
    };
  } catch (error) {
    // Rollback transaksi jika ada error
    await transaction.rollback();
    const errorMessage = error.message || "An error occurred during updating MOM.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function enabled(id, params) {
  try {
    const mom = await dbSAPPS.Mom.findByPk(id);
    if (!mom)
      return {
        success: false,
        message: "mom not found!",
      };

    const updateData = {};
    updateData.enabled = params.enabled;
    if (params.modified_by) updateData.modified_by = params.modified_by;
    if (params.modified) updateData.modified = params.modified;

    await mom.update(updateData);

    return {
      success: true,
      message: "Mom has been updated!",
    };
  } catch (error) {
    const errorMessage = error.message || "Failed to Update mom.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function _delete(id) {
  let transaction;
  try {
    transaction = await dbSAPPS.sequelize.transaction();
    const mom = await dbSAPPS.Mom.findByPk(id, { transaction });
    if (!mom) return { success: false, message: "MOM not found!" };

    const momFiles = await dbSAPPS.MomFile.findAll({
      where: {
        mom_id: id,
      },
      transaction,
    });

    if (momFiles.length > 0) {
      try {
        // Hapus file lama
        await Promise.all(
          momFiles.map(async (file) => {
            const filePath = path.join(__dirname, "../../../../public/data/documents/", file.filename);
            await fs.promises.unlink(filePath);
          })
        );
      } catch (err) {
        console.warn("Gagal hapus file lama:", err.message);
        // Bisa lanjut tanpa gagal
      }
    }
    await mom.destroy({ transaction });

    await transaction.commit();
    return {
      success: true,
      message: "Mom successfully deleted!",
    };
  } catch (error) {
    if (transaction) await transaction.rollback();
    const errorMessage = error.message || "Failed to delete Mom.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}
