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

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

const formatWithModifier = async (gimmickRequests) => {
  return Promise.all(
    gimmickRequests.map(async (gimmickRequest) => {
      const modifier = await dbSAPPS.User.findOne({
        where: {
          id: gimmickRequest.modified_by,
        },
        attributes: ["full_name"],
      });

      return {
        ...gimmickRequest,
        modifier: modifier?.full_name,
      };
    })
  );
};

async function getAll(q) {
  try {
    const params = q.params;
    const filterConditions = {};
    if (params?.is_workflow_direct === true || params?.is_workflow_direct === "true") {
      if (params.doc_id) {
        filterConditions.id = {
          [Op.eq]: parseInt(params.doc_id),
        };
      }
    } else {
      if (params.access_read_all_data === true || params.access_read_all_data === "true") {
        filterConditions.territory_id = {
          [Op.not]: null,
        };
      } else {
        if (params.territory_id) {
          if (Array.isArray(params.territory_id)) {
            filterConditions.territory_id = {
              [Op.in]: params?.territory_id?.map((id) => parseInt(id)) || [],
            };
          } else {
            filterConditions.territory_id = {
              [Op.eq]: parseInt(params.territory_id),
            };
          }
        }
      }
    }

    const fses = await dbSAPPS.Fse.findAll({
      order: [["modified", "DESC"]],
      where: filterConditions,
      include: [
        {
          model: dbSAPPS.Company,
          attributes: ["id", "display_name"],
          as: "company",
        },
        {
          model: dbSAPPS.Territory,
          attributes: ["id", "display_name"],
          as: "territory",
        },
        {
          model: dbSAPPS.Period,
          attributes: ["id", "display_name"],
          as: "period",
        },
        {
          model: dbSAPPS.FseItem,
          as: "fseitems",
          attributes: ["id", "fse_id", "customer_id", "item_id", "sku_code", "quantity"],
          include: [
            {
              model: dbSAPPS.Item,
              as: "item",
              attributes: ["id", "display_name", "sku_code"],
            },
            {
              model: dbSAPPS.CustomerList,
              as: "customer",
              // attributes: ["id", "display_name"],
            },
          ],
        },
        {
          model: dbSAPPS.User,
          as: "user",
          include: [
            {
              model: dbSAPPS.Employee,
              as: "employee",
              attributes: ["employee_name"],
              include: [
                {
                  model: dbSAPPS.Designation,
                  as: "designation",
                  attributes: ["display_name"],
                },
              ],
            },
          ],
        },
      ],
    });

    const workflows = await dbSAPPS.Workflow.findAll({
      where: {
        doc_id: {
          [Op.in]: fses.map((item) => item.id),
        },
        doctype_id: 155,
      },
      attributes: ["id", "doc_id", "doctype_id", "status", "modified_by", "modified"],
      include: [
        {
          model: dbSAPPS.WorkflowApprover,
          as: "workflowapprovers",
          attributes: ["id", "workflow_id", "designation_id", "territory_id", "status", "modified"],
          include: [
            {
              model: dbSAPPS.Designation,
              as: "designation",
              attributes: ["id", "name", "display_name"],
              include: [
                {
                  model: dbSAPPS.Employee,
                  as: "employee",
                  attributes: ["id", "employee_name"],
                },
              ],
            },
            {
              model: dbSAPPS.Territory,
              as: "territory",
              attributes: ["id", "name", "display_name"],
              include: [
                {
                  model: dbSAPPS.Employee,
                  as: "employees",
                  attributes: ["id", "employee_name"],
                  include: [
                    {
                      model: dbSAPPS.Designation,
                      as: "designation",
                      attributes: ["display_name"],
                    },
                  ],
                },
              ],
            },
          ],
        },
      ],
    });

    const data = fses.map((item) => {
      const workflow = workflows.find((wf) => wf.doc_id === item.id);
      return {
        ...item.dataValues,
        workflow: workflow ? workflow.dataValues : null,
      };
    });

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

async function option() {
  try {
    const fses = await dbSAPPS.Fse.findAll({
      attributes: ["id", "territory_id", "name", "company_id", "period_id"],
      where: { enabled: true },
      order: [["name", "ASC"]],
      include: [
        {
          model: dbSAPPS.Company,
          as: "company",
          attributes: ["id", "display_name"],
        },
      ],
    });

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

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

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

async function create(params) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    // Pastikan parameter yang diperlukan ada
    if (!params.territory_id || !params.period_id) {
      return {
        success: false,
        message: "Name, display name, valid from, valid to & company are required!",
      };
    }

    // 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
    if (!params.owner) params.owner = 1; // Default jika tidak ada nilai

    // periksa apakah data dengan territory_id, year_id, period_id sudah ada di dalam database
    const existingData = await dbSAPPS.Fse.findOne({
      where: {
        territory_id: params.territory_id,
        period_id: params.period_id,
        company_id: params.company_id,
      },
    });
    if (existingData) {
      return { success: false, message: `FSE this month is already exists.` };
    }

    // Generate FSE Number
    const generateFSE = async () => {
      return `FSE-${params.territory_name}-${params.period_name}`;
    };

    // Generate the new FSE number
    const newFSENumber = await generateFSE();

    // Set default value untuk enabled
    if (!params.enabled) params.enabled = true;

    const newParams = {
      ...params,
      name: newFSENumber,
    };

    // Buat call plan baru
    const fse = await dbSAPPS.Fse.create(newParams, { transaction });

    // Cek dan proses jika ada callplandestinations
    if (params.fseitems && params.fseitems.length > 0) {
      // Pastikan `fseitems` adalah array yang valid
      if (typeof params.fseitems === "string") {
        try {
          params.fseitems = JSON.parse(params.fseitems);
        } catch (err) {
          return {
            success: false,
            message: "Invalid JSON format for fse items",
          };
        }
      }

      // Pastikan bahwa `fseitems` adalah array yang valid dan memiliki data
      if (Array.isArray(params.fseitems) && params.fseitems.length > 0) {
        // Check unique data fseitems outlet_id dan client_id
        const duplicates = params.fseitems.filter(
          (item, index) =>
            params.fseitems.findIndex((d) => d.customer_id === item.customer_id && d.item_id === item.item_id) !== index
        );
        if (duplicates.length > 0) {
          await transaction.rollback();
          return {
            success: false,
            message: `Duplicate entries exist in fse items for display names: ${duplicates.join(
              ", "
            )}. Transaction rolled back.`,
          };
        }

        // Persiapkan data anak untuk disimpan
        const fseItemData = params.fseitems.map((items) => ({
          ...items,
          creation: Date.now(),
          modified: Date.now(),
          modified_by: params.modified_by || 1,
          owner: params.owner || 1,
          fse_id: fse.id, // Assign ID dari FSE yang baru saja dibuat
        }));

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

    // buat workflow approval
    if (params?.workflowTerritories) {
      if (Array.isArray(params?.workflowTerritories) && params?.workflowTerritories.length > 0) {
        const workflowSettings = await dbSAPPS.WorkflowSetting.findAll(
          {
            where: {
              doctype_id: params.doctype_id,
              type: "Territory",
              enabled: true,
            },
          },
          { transaction }
        );
        const limitWorkflow = workflowSettings[0]?.limit || 0;
        const workflowTerritories = params?.workflowTerritories.slice(0, limitWorkflow);

        if (!workflowTerritories || workflowTerritories.length === 0) {
          await transaction.rollback();
          return {
            success: false,
            message: `Workflow Territories is required. Transaction rolled back.`,
          };
        }

        const workflowData = {
          creation: Date.now(),
          modified: Date.now(),
          modified_by: params.modified_by || 1,
          owner: params.owner || 1,
          doctype_id: params.doctype_id,
          doc_id: fse?.id,
          status: "Draft",
        };

        const workflow = await dbSAPPS.Workflow.create(workflowData, {
          transaction,
          lock: transaction.LOCK.UPDATE,
        });

        if (workflow) {
          const workflowApproversData = workflowTerritories?.map((workflowTerritory) => ({
            creation: Date.now(),
            modified: Date.now(),
            modified_by: params.modified_by || 1,
            owner: params.owner || 1,
            workflow_id: workflow.id,
            territory_id: workflowTerritory?.territory_id,
            status: null,
          }));

          const approvers = await dbSAPPS.WorkflowApprover.bulkCreate(workflowApproversData, {
            transaction,
            lock: transaction.LOCK.UPDATE,
          });
          if (
            approvers?.length !== workflowTerritories.length ||
            !approvers.every((approver) => approver.workflow_id === workflow.id && approver.territory_id !== null)
          ) {
            await transaction.rollback();
            return {
              success: false,
              message: "Failed to create workflow approvers. Please try again later.",
            };
          }
        }
      }
    }

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

async function update(id, params) {
  const transaction = await dbSAPPS.sequelize.transaction();

  try {
    const fse = await dbSAPPS.Fse.findByPk(id);
    if (!fse)
      return {
        success: false,
        message: "FSE not found!",
      };

    // periksa apakah params.callplandestinations lenght nya > 0 atau tidak
    if (params.fseitems.length === 0) {
      return {
        success: false,
        message: `Please select fse item berfore saving!`,
      };
    }

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

    // Update fse
    const updateData = {
      ...params,
      modified: Date.now(),
      modified_by: params.modified_by || fse.modified_by || 1,
    };
    const result = await fse.update(updateData, { transaction });

    // Cek dan proses jika ada callplandestinations
    if (params.fseitems && params.fseitems.length > 0) {
      // Pastikan `fseitems` adalah array yang valid
      if (typeof params.fseitems === "string") {
        try {
          params.fseitems = JSON.parse(params.fseitems);
        } catch (err) {
          return {
            success: false,
            message: "Invalid JSON format for fse items",
          };
        }
      }

      // Pastikan bahwa `fseitems` adalah array yang valid dan memiliki data
      if (Array.isArray(params.fseitems) && params.fseitems.length > 0) {
        // Check unique data fseitems outlet_id dan client_id
        const duplicates = params.fseitems.filter(
          (item, index) =>
            params.fseitems.findIndex((d) => d.customer_id === item.customer_id && d.item_id === item.item_id) !== index
        );
        if (duplicates.length > 0) {
          await transaction.rollback();
          return {
            success: false,
            message: `Duplicate entries exist in fse items for display names: ${duplicates.join(
              ", "
            )}. Transaction rolled back.`,
          };
        }

        // Persiapkan data anak untuk disimpan
        const fseItemData = params.fseitems.map((items) => ({
          ...items,
          creation: Date.now(),
          modified: Date.now(),
          modified_by: params.modified_by || 1,
          owner: params.owner || 1,
          fse_id: fse.id, // Assign ID dari FSE yang baru saja dibuat
        }));

        // Update data anak menggunakan bulkCreate
        await dbSAPPS.FseItem.bulkCreate(fseItemData, {
          updateOnDuplicate: ["modified", "modified_by", "owner"],
          transaction,
        });

        // Hapus data yang dihapus
        const deletedItems = (
          await dbSAPPS.FseItem.findAll({
            where: {
              fse_id: fse.id,
              id: {
                [Op.notIn]: params.fseitems.map((d) => d.id),
              },
            },
          })
        ).map((d) => d.id);
        if (deletedItems.length > 0) {
          await dbSAPPS.FseItem.destroy({
            where: {
              id: deletedItems,
            },
            transaction,
          });
        }
      }
    }

    // Update workflow approval
    if (params?.workflowTerritories) {
      if (Array.isArray(params?.workflowTerritories) && params?.workflowTerritories.length > 0) {
        const workflowSettings = await dbSAPPS.WorkflowSetting.findAll(
          {
            where: {
              doctype_id: params.doctype_id,
              type: "Territory",
              enabled: true,
            },
          },
          { transaction }
        );
        const limitWorkflow = workflowSettings[0]?.limit || 0;
        const workflowTerritories = params?.workflowTerritories.slice(0, limitWorkflow);

        if (!workflowTerritories || workflowTerritories.length === 0) {
          await transaction.rollback();
          return {
            success: false,
            message: `Workflow Territories is required. Transaction rolled back.`,
          };
        }

        const workflowData = {
          creation: Date.now(),
          modified: Date.now(),
          modified_by: params.modified_by || 1,
          owner: params.owner || 1,
          doctype_id: params.doctype_id,
          doc_id: fse?.id,
          status: "Draft",
        };

        const workflow = await dbSAPPS.Workflow.create(workflowData, {
          transaction,
          lock: transaction.LOCK.UPDATE,
        });

        if (workflow) {
          const workflowApproversData = workflowTerritories?.map((workflowTerritory) => ({
            creation: Date.now(),
            modified: Date.now(),
            modified_by: params.modified_by || 1,
            owner: params.owner || 1,
            workflow_id: workflow.id,
            territory_id: workflowTerritory?.territory_id,
            status: null,
          }));

          const approvers = await dbSAPPS.WorkflowApprover.bulkCreate(workflowApproversData, {
            transaction,
            lock: transaction.LOCK.UPDATE,
          });
          if (
            approvers?.length !== workflowTerritories.length ||
            !approvers.every((approver) => approver.workflow_id === workflow.id && approver.territory_id !== null)
          ) {
            await transaction.rollback();
            return {
              success: false,
              message: "Failed to create workflow approvers. Please try again later.",
            };
          }
        }
      }
    }

    // Commit transaksi jika semua berhasil
    await transaction.commit();
    return {
      success: true,
      message: `FSE has been updated!`,
    };
  } catch (error) {
    // Rollback transaksi jika ada error
    await transaction.rollback();
    const errorMessage = error.message || `An error occurred during updating fse.`;
    return {
      success: false,
      message: errorMessage,
    };
  }
}
async function enabled(id, params) {
  try {
    const clienttype = await dbSAPPS.Fse.findByPk(id);
    if (!clienttype)
      return {
        success: false,
        message: "Data 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 clienttype.update(updateData);

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

async function _delete(id) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    const fse = await dbSAPPS.Fse.findByPk(id);

    if (!fse) return { success: false, message: "FSE not found!" };
    const workflows = await dbSAPPS.Workflow.findAll({
      where: {
        doc_id: {
          [Op.eq]: fse.id,
        },
        doctype_id: 155,
      },
      attributes: ["id", "doc_id", "doctype_id", "status", "modified_by", "modified"],
      include: [
        {
          model: dbSAPPS.WorkflowApprover,
          as: "workflowapprovers",
          attributes: ["id", "workflow_id", "designation_id", "territory_id", "status", "modified"],
          include: [
            {
              model: dbSAPPS.Designation,
              as: "designation",
              attributes: ["id", "name", "display_name"],
              include: [
                {
                  model: dbSAPPS.Employee,
                  as: "employee",
                  attributes: ["id", "employee_name"],
                },
              ],
            },
            {
              model: dbSAPPS.Territory,
              as: "territory",
              attributes: ["id", "name", "display_name"],
              include: [
                {
                  model: dbSAPPS.Employee,
                  as: "employees",
                  attributes: ["id", "employee_name"],
                },
              ],
            },
          ],
        },
      ],
    });
    if (!workflows)
      return {
        success: false,
        message: "Workflows not found!",
      };
    for (const workflow of workflows) {
      if (workflow) {
        await dbSAPPS.WorkflowApprover.destroy({
          where: { workflow_id: workflow.id },
          transaction,
        });
        await dbSAPPS.Workflow.destroy({
          where: { id: workflow.id },
          transaction,
        });
      }
    }
    await new Promise((resolve) => setTimeout(resolve, 500));
    await fse.destroy({ transaction });

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