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

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

async function getAll() {
  try {
    // Mengambil semua pengguna dan mengurutkannya berdasarkan kolom 'modified' secara menurun
    const workplanMonitors = await dbSAPPS.WorkplanMonitor.findAll({
      order: [["modified", "DESC"]],
      include: [
        {
          model: dbSAPPS.Department,
          as: "owner_info",
          attributes: ["display_name"],
        },
        {
          model: dbSAPPS.Department,
          as: "counterpart_info",
          attributes: ["display_name"],
        },
        {
          model: dbSAPPS.WorkplanMonitorChild,
          as: "workplanmonitorchilds",
          attributes: [
            "id",
            "workplanmonitor_id",
            "activity",
            "description",
            "start_date",
            "end_date",
            "extend_startdate",
            "extend_date",
            "pic",
            "status",
            "progress",
            "note",
            "score",
          ],
          include: [
            {
              model: dbSAPPS.WorkplanMonitorActivityChild,
              as: "workplanmonitoractivitychilds",
              attributes: [
                "id",
                "status",
                "progress",
                "note",
                "chat",
                "owner_note",
                "counterpart_note",
                "workplanmonitorchild_id",
                "modified_by",
                "modified",
              ],
            },
          ],
        },
        {
          model: dbSAPPS.Company,
          as: "company",
          attributes: ["id", "name"],
        },
      ],
    });

    // Ambil semua `modified_by` yang unik dari seluruh `workplanmonitoractivitychilds`
    const modifiedByIds = [
      ...new Set(
        workplanMonitors.flatMap((workplanMonitor) =>
          workplanMonitor.workplanmonitorchilds.flatMap((wc) =>
            wc.workplanmonitoractivitychilds.map((wca) => wca.modified_by)
          )
        )
      ),
    ];

    // Query User berdasarkan `modified_by` yang unik
    const users = await dbSAPPS.User.findAll({
      where: { id: modifiedByIds },
      attributes: ["id", "full_name"],
    });

    // Map hasil user ke dalam objek untuk akses cepat
    const userMap = users.reduce((acc, user) => {
      acc[user.id] = user.full_name;
      return acc;
    }, {});

    const workplanMonitorsData = await Promise.all(
      workplanMonitors.map(async (workplanMonitor) => {
        // Untuk setiap workplanmonitorchilds dan workplanmonitoractivitychilds, tambahkan modifier
        const modifiedData = workplanMonitor.workplanmonitorchilds.map((wc) => {
          const updatedActivityChildren = wc.workplanmonitoractivitychilds.map((wca) => ({
            ...wca.dataValues,
            modifier: userMap[wca.modified_by] || null, // Tambahkan modifier dengan full_name
          }));

          return {
            ...wc.dataValues,
            workplanmonitoractivitychilds: updatedActivityChildren,
          };
        });

        return {
          ...workplanMonitor.dataValues,
          workplanmonitorchilds: modifiedData,
        };
      })
    );

    // Mengembalikan respons dengan status 200 OK
    return {
      workplanMonitors: workplanMonitorsData,
      success: true,
      message: "workplanMonitors loaded successfully!",
    };
  } catch (error) {
    // Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
    const errorMessage = error.message || "Failed to load workplanMonitors!";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function getByEmpID(params) {
  try {
    const workplanMonitors = await dbSAPPS.WorkplanMonitor.findAll({
      order: [["modified", "DESC"]],
      include: [
        {
          model: dbSAPPS.Department,
          as: "owner_info",
          attributes: ["display_name"],
        },
        {
          model: dbSAPPS.Department,
          as: "counterpart_info",
          attributes: ["display_name"],
        },
        {
          model: dbSAPPS.WorkplanMonitorChild,
          as: "workplanmonitorchilds",
          attributes: [
            "id",
            "workplanmonitor_id",
            "activity",
            "description",
            "start_date",
            "extend_startdate",
            "extend_date",
            "end_date",
            "pic",
            "status",
            "progress",
            "note",
            "score",
          ],
          include: [
            {
              model: dbSAPPS.WorkplanMonitorActivityChild,
              as: "workplanmonitoractivitychilds",
              attributes: ["id", "status", "progress", "note", "workplanmonitorchild_id"],
            },
          ],
        },
        {
          model: dbSAPPS.Company,
          as: "company",
          attributes: ["id", "name"],
        },
      ],
    });

    // Jika terdapat params.employee_id maka lakukan filtering data
    if (params.employee_id) {
      const empID = String(params.employee_id);
      // Proses filter data
      const filteredWorkplans = workplanMonitors
        .map((workplan) => {
          // Filter child yang memiliki properti 'pic'
          const filteredChilds = workplan.workplanmonitorchilds.filter((child) => {
            // Pastikan field pic tidak kosong
            if (child.pic) {
              try {
                // Karena field pic berupa string JSON, kita harus parse terlebih dahulu
                const picArray = JSON.parse(child.pic);
                // Cek apakah salah satu objek di picArray memiliki property id yang sama
                return picArray.some((picObj) => String(picObj.id) === empID);
              } catch (e) {
                // Jika parsing gagal, abaikan data tersebut
                return false;
              }
            }
            return false;
          });
          // Jika terdapat minimal 1 child yang cocok, kembalikan data dengan data yang sudah difilter
          if (filteredChilds.length > 0) {
            // Jika menggunakan Sequelize, untuk menghindari masalah instance atau dataValues, kita bisa cloning data
            return {
              ...workplan.dataValues,
              workplanmonitorchilds: filteredChilds,
            };
          }
          // Jika tidak ada child yang cocok, data tersebut tidak ditampilkan
          return null;
        })
        .filter((item) => item !== null);

      return {
        workplanMonitors: filteredWorkplans,
        success: true,
        message: "Workplan loaded successfully!",
      };
    }

    // Mengembalikan respons dengan status 200 OK
    return {
      workplanMonitors,
      success: true,
      message: "Workplan loaded successfully!",
    };
  } catch (error) {
    // Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
    const errorMessage = error.message || "Failed to load workplanMonitors!";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function filter(params) {
  // Membuat objek filter dengan validasi
  const filterConditions = {};

  if (params.department) {
    filterConditions.counterpart_id = {
      [Op.eq]: params.department,
    };
  }

  if (params.enabled) {
    filterConditions.enabled = {
      [Op.eq]: params.enabled === "1" ? true : false,
    };
  }
  try {
    // Mencari pengguna berdasarkan filter conditions
    const workplanMonitors = await dbSAPPS.WorkplanMonitor.findAll({
      where: filterConditions,
      order: [["modified", "DESC"]],
      include: [
        {
          model: dbSAPPS.Department,
          as: "owner_info",
          attributes: ["display_name"],
        },
        {
          model: dbSAPPS.Department,
          as: "counterpart_info",
          attributes: ["display_name"],
        },
        {
          model: dbSAPPS.WorkplanMonitorChild,
          as: "workplanmonitorchilds",
          attributes: [
            "id",
            "workplanmonitor_id",
            "activity",
            "description",
            "start_date",
            "end_date",
            "extend_startdate",
            "extend_date",
            "pic",
            "status",
            "progress",
            "note",
            "score",
          ],
          include: [
            {
              model: dbSAPPS.WorkplanMonitorActivityChild,
              as: "workplanmonitoractivitychilds",
              attributes: ["id", "status", "progress", "note"],
            },
          ],
        },
        {
          model: dbSAPPS.Company,
          as: "company",
          attributes: ["name"],
        },
      ],
    });

    // Mengembalikan hasil pencarian
    return {
      success: true,
      workplanMonitors,
      message: "workplanMonitors loaded successfully!",
    };
  } catch (error) {
    // Logging error untuk keperluan debugging
    console.error("Error retrieving workplanMonitors: ", error);
    const errorMessage = error.message || "Failed to retrieve workplanMonitors. Please try again later.";
    // Mengembalikan respons dengan status 500 Internal Server Error
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function option() {
  try {
    // Mencari pengguna yang diaktifkan dengan atribut tertentu
    const workplanMonitors = await dbSAPPS.WorkplanMonitor.findAll({
      attributes: ["id", "name", "display_name"],
      where: { enabled: true },
      order: [["name", "ASC"]],
      include: [
        {
          model: dbSAPPS.Department,
          as: "owner_info",
          attributes: ["display_name"],
        },
        {
          model: dbSAPPS.Department,
          as: "counterpart_info",
          attributes: ["display_name"],
        },
        {
          model: dbSAPPS.WorkplanMonitorChild,
          as: "workplanmonitorchilds",
          attributes: [
            "id",
            "workplanmonitor_id",
            "activity",
            "description",
            "start_date",
            "end_date",
            "extend_startdate",
            "extend_date",
            "pic",
            "status",
            "progress",
            "note",
            "score",
          ],
          include: [
            {
              model: dbSAPPS.WorkplanMonitorActivityChild,
              as: "workplanmonitoractivitychilds",
              attributes: ["id", "status", "progress", "note"],
            },
          ],
        },
        {
          model: dbSAPPS.Company,
          as: "company",
          attributes: ["name"],
        },
      ],
    });

    // Mengembalikan hasil pencarian
    return {
      success: true,
      workplanMonitors,
      message: "workplanMonitors loaded successfully!",
    };
  } catch (error) {
    // Logging error untuk keperluan debugging
    console.error("Error retrieving workplanMonitors: ", error);
    const errorMessage = error.message || "Failed to retrieve workplanMonitors. Please try again later.";
    // Mengembalikan respons dengan status 500 Internal Server Error
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function count() {
  try {
    // Menghitung jumlah pengguna yang diaktifkan
    const count = await dbSAPPS.WorkplanMonitor.count({
      where: { enabled: true },
    });

    // Mengembalikan hasil hitung
    return {
      success: true,
      count,
      message: "workplanMonitors loaded successfully!",
    };
  } catch (error) {
    // Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
    console.error("Error counting workplanMonitors: ", error);
    return {
      success: false,
      message: "Failed to retrieve workplanMonitors count. Please try again later.",
    };
  }
}

async function create(params) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    // Validasi input
    if (!params.name)
      return {
        success: false,
        message: "Project name is required!",
      };

    // Periksa apakah nama dengan company yang sama sudah digunakan
    const existingWorkplanMonitorName = await dbSAPPS.WorkplanMonitor.findOne({
      where: {
        name: params.name,
        company_id: params.company_id,
      },
    });

    if (existingWorkplanMonitorName)
      return {
        success: false,
        message: `WorkplanMonitor "${params.name}" with the same company is already taken.`,
      };

    if (!params.enabled) params.enabled = true;

    const newWorkplanMonitor = await dbSAPPS.WorkplanMonitor.create(params, {
      transaction,
    });

    // Proses workplanmonitorchilds jika ada
    if (params.workplanmonitorchilds) {
      // Pastikan data adalah array
      if (typeof params.workplanmonitorchilds === "string") {
        params.workplanmonitorchilds = JSON.parse(params.workplanmonitorchilds);
      }

      // Validasi dan persiapkan data untuk bulkCreate
      const workplanMonitorsChildData = params.workplanmonitorchilds.map((workplanMonitorChild) => {
        // Validasi field yang diperlukan
        if (!workplanMonitorChild.activity) {
          throw new Error("Missing required fields in wp child.");
        }

        return {
          ...workplanMonitorChild,
          creation: Date.now(),
          modified: Date.now(),
          modified_by: params.modified_by,
          owner: params.owner,
          workplanmonitor_id: newWorkplanMonitor.id,
        };
      });

      // Lakukan bulkCreate untuk children
      const createdChildren = await dbSAPPS.WorkplanMonitorChild.bulkCreate(workplanMonitorsChildData, {
        transaction,
      });

      // Proses workplanmonitoractivitychilds jika ada
      if (params.workplanmonitorchilds) {
        // Loop through each child to get its activities
        for (let i = 0; i < createdChildren.length; i++) {
          const child = createdChildren[i];
          const activitiesForChild = params.workplanmonitorchilds[i].workplanmonitoractivitychilds;

          if (activitiesForChild && activitiesForChild.length > 0) {
            const workplanMonitorsActivityChildData = activitiesForChild.map((workplanMonitorActivityChild) => {
              // Validasi field yang diperlukan
              if (!workplanMonitorActivityChild.status) {
                throw new Error("Missing required fields in activity child.");
              }

              return {
                ...workplanMonitorActivityChild,
                creation: Date.now(),
                modified: Date.now(),
                modified_by: params.modified_by,
                owner: params.owner,
                workplanmonitorchild_id: child.id, // Associate with the correct child
              };
            });

            // Lakukan bulkCreate untuk activities
            await dbSAPPS.WorkplanMonitorActivityChild.bulkCreate(workplanMonitorsActivityChildData, {
              transaction,
            });
          }
        }
      }
    }

    // Commit transaksi jika semua berhasil
    await transaction.commit();
    return {
      success: true,
      message: "Data Workplan Monitor has been successfully added!",
      workplanMonitors: newWorkplanMonitor,
    };
  } catch (error) {
    // Rollback transaksi jika terjadi kesalahan
    await transaction.rollback();
    const errorMessage = error.message || "An error occurred during Workplan monitor creation.";
    console.error("Error creating workplan monitor:", error); // Log kesalahan untuk debugging
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function update(id, params) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    const workplanMonitor = await dbSAPPS.WorkplanMonitor.findByPk(id);
    if (!workplanMonitor) return { success: false, message: "Workplan not found!" };

    await workplanMonitor.update(params, { transaction });

    if (params.workplanmonitorchilds) {
      // Hapus activity child dan child yang ada
      const existingChildren = await dbSAPPS.WorkplanMonitorChild.findAll({
        where: { workplanmonitor_id: id },
        transaction,
      });

      for (const child of existingChildren) {
        await dbSAPPS.WorkplanMonitorActivityChild.destroy({
          where: { workplanmonitorchild_id: child.id },
          transaction,
        });
      }

      await dbSAPPS.WorkplanMonitorChild.destroy({
        where: { workplanmonitor_id: id },
        transaction,
      });

      // 1. Ganti bulkCreate dengan create individual
      const createdChildren = [];
      for (const childData of params.workplanmonitorchilds) {
        // Validasi field
        if (!childData.activity) {
          throw new Error("Missing required fields in workplan monitor child.");
        }

        // Buat child satu per satu
        const newChild = await dbSAPPS.WorkplanMonitorChild.create(
          {
            ...childData,
            creation: Date.now(),
            modified: Date.now(),
            enabled: true,
            modified_by: params.modified_by,
            owner: params.owner,
            workplanmonitor_id: id,
          },
          { transaction }
        );
        createdChildren.push(newChild);

        // 2. Proses activity childs langsung setelah child dibuat
        if (childData.workplanmonitoractivitychilds?.length > 0) {
          const activityChildsData = childData.workplanmonitoractivitychilds.map((activity) => ({
            ...activity,
            creation: Date.now(),
            modified: Date.now(),
            modified_by: params.modified_by,
            owner: params.owner,
            workplanmonitorchild_id: newChild.id, // Gunakan ID yang baru dibuat
          }));

          await dbSAPPS.WorkplanMonitorActivityChild.bulkCreate(activityChildsData, {
            transaction,
          });
        }
      }
    }

    await transaction.commit();
    return { success: true, message: "Workplan Monitor updated successfully!" };
  } catch (error) {
    await transaction.rollback();
    console.error("Error:", error);
    return { success: false, message: error.message };
  }
}

async function updateProgressList(id, params) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    const progressList = await dbSAPPS.WorkplanMonitorActivityChild.findByPk(id);
    if (!progressList) return { success: false, message: "progress list not found!" };

    await progressList.update(params, { transaction });

    await transaction.commit();
    return { success: true, message: "Progress list updated successfully!" };
  } catch (error) {
    await transaction.rollback();
    console.error("Error:", error);
    return { success: false, message: error.message };
  }
}

async function enabled(id, params) {
  try {
    const workplanMonitor = await dbSAPPS.WorkplanMonitor.findByPk(id);
    if (!workplanMonitor)
      return {
        success: false,
        message: "WorkplanMonitor 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 workplanMonitor.update(updateData);

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

async function _delete(id) {
  try {
    // Mengambil pengguna dari database
    const workplanMonitor = await dbSAPPS.WorkplanMonitor.findByPk(id);
    if (!workplanMonitor) return { success: false, message: "WorkplanMonitor not found!" };

    // Menghapus pengguna dari database
    await workplanMonitor.destroy();

    // Respons sukses
    return {
      success: true,
      message: "WorkplanMonitor successfully deleted!",
    };
  } catch (error) {
    const errorMessage = error.message || "Failed to delete workplanMonitor.";
    // Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
    return {
      success: false,
      message: errorMessage,
    };
  }
}
