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

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

async function getAll(params) {
    try {
        const filterConditions = {};

        if ((params.access_read_all_data === true || params.access_read_all_data === "true") || (params.administrator_of_pirlo === true || params.administrator_of_pirlo === "true")) {
            filterConditions.shipper = {
                [Op.ne]: null,
            };
        } else {
            if (params.employeesId && params.employeesId.length > 0) {
                filterConditions.shipper = {
                    [Op.in]: params.employeesId.map(item => parseInt(item)),
                };
            } else {
                if (params.employee_id) {
                    filterConditions.shipper = {
                        [Op.eq]: parseInt(params.employee_id),
                    };
                }
            }
        }

        const goodsReceipts = await dbSAPPS.GoodsReceipt.findAll({
            where: filterConditions,
            order: [["modified", "DESC"]],
        });

        const goodsReceiptsPromises = goodsReceipts.map(async (goodsReceipt) => {
            const employeePromises = [];

            if (goodsReceipt.shipper) {
                employeePromises.push(
                    dbSAPPS.Employee.findOne({
                        where: { id: goodsReceipt.shipper },
                        attributes: ["id", "employee_name", "company_id"],
                        include: [
                            {
                                model: dbSAPPS.Company,
                                as: "company",
                                attributes: ["id", "display_name"],
                            },
                        ],
                    })
                );
            }

            if (goodsReceipt.cosignee) {
                employeePromises.push(
                    dbSAPPS.Employee.findOne({
                        where: { id: goodsReceipt.cosignee },
                        attributes: ["id", "employee_name", "company_id"],
                        include: [
                            {
                                model: dbSAPPS.Company,
                                as: "company",
                                attributes: ["id", "display_name"],
                            },
                        ],
                    })
                );
            }

            const [shipper, cosignee] = await Promise.all(employeePromises);

            return {
                ...goodsReceipt.dataValues,
                shipper_name: shipper ? shipper.employee_name : null,
                cosignee_name: cosignee ? cosignee.employee_name : null,
                shipper_company_name: shipper ? shipper.company.display_name : null,
                cosignee_company_name: cosignee ? cosignee.company.display_name : null,
            };
        });

        const goodsReceiptsWithEmployeeNames = await Promise.all(goodsReceiptsPromises);

        return {
            goodsReceipts: goodsReceiptsWithEmployeeNames,
            success: true,
            message: "goods receipts loaded successfully!",
        };
    } catch (error) {
        const errorMessage = error.message || "Failed to load goods receipts!";
        return {
            success: false,
            message: errorMessage,
        };
    }
}

async function getAllShipper(params) {
    try {
        const filterConditions = {};

        if ((params.access_read_all_data === true || params.access_read_all_data === "true") || (params.administrator_of_pirlo === true || params.administrator_of_pirlo === "true")) {
            filterConditions.shipper = {
                [Op.ne]: null,
            };
        } else {
            if (params.employeesId && params.employeesId.length > 0) {
                filterConditions.shipper = {
                    [Op.in]: params.employeesId.map(item => parseInt(item)),
                };
            } else {
                if (params.employee_id) {
                    filterConditions.shipper = {
                        [Op.eq]: parseInt(params.employee_id),
                    };
                }
            }
        }

        const goodsReceipts = await dbSAPPS.GoodsReceipt.findAll({
            where: filterConditions,
            order: [["modified", "DESC"]],
        });

        const goodsReceiptsPromises = goodsReceipts.map(async (goodsReceipt) => {
            const employeePromises = [];

            if (goodsReceipt.shipper) {
                employeePromises.push(
                    dbSAPPS.Employee.findOne({
                        where: { id: goodsReceipt.shipper },
                        attributes: ["id", "employee_name", "company_id"],
                        include: [
                            {
                                model: dbSAPPS.Company,
                                as: "company",
                                attributes: ["id", "display_name"],
                            },
                        ],
                    })
                );
            }

            if (goodsReceipt.cosignee) {
                employeePromises.push(
                    dbSAPPS.Employee.findOne({
                        where: { id: goodsReceipt.cosignee },
                        attributes: ["id", "employee_name", "company_id"],
                        include: [
                            {
                                model: dbSAPPS.Company,
                                as: "company",
                                attributes: ["id", "display_name"],
                            },
                        ],
                    })
                );
            }

            const [shipper, cosignee] = await Promise.all(employeePromises);

            return {
                ...goodsReceipt.dataValues,
                shipper_name: shipper ? shipper.employee_name : null,
                cosignee_name: cosignee ? cosignee.employee_name : null,
                shipper_company_name: shipper ? shipper.company.display_name : null,
                cosignee_company_name: cosignee ? cosignee.company.display_name : null,
            };
        });

        const goodsReceiptsWithEmployeeNames = await Promise.all(goodsReceiptsPromises);

        return {
            goodsReceipts: goodsReceiptsWithEmployeeNames,
            success: true,
            message: "goods receipts loaded successfully!",
        };
    } catch (error) {
        const errorMessage = error.message || "Failed to load goods receipts!";
        return {
            success: false,
            message: errorMessage,
        };
    }
}

async function getAllCosignee(params) {
    try {
        const filterConditions = {};

        if ((params.access_read_all_data === true || params.access_read_all_data === "true") || (params.administrator_of_pirlo === true || params.administrator_of_pirlo === "true")) {
            filterConditions.cosignee = {
                [Op.ne]: null,
            };
        } else {
            if (params.employeesId && params.employeesId.length > 0) {
                filterConditions.cosignee = {
                    [Op.in]: params.employeesId.map(item => parseInt(item)),
                };
            } else {
                if (params.employee_id) {
                    filterConditions.cosignee = {
                        [Op.eq]: parseInt(params.employee_id),
                    };
                }
            }
        }

        const goodsReceipts = await dbSAPPS.GoodsReceipt.findAll({
            where: filterConditions,
            order: [["modified", "DESC"]],
        });

        const goodsReceiptsPromises = goodsReceipts.map(async (goodsReceipt) => {
            const employeePromises = [];

            if (goodsReceipt.shipper) {
                employeePromises.push(
                    dbSAPPS.Employee.findOne({
                        where: { id: goodsReceipt.shipper },
                        attributes: ["id", "employee_name", "company_id"],
                        include: [
                            {
                                model: dbSAPPS.Company,
                                as: "company",
                                attributes: ["id", "display_name"],
                            },
                        ],
                    })
                );
            }

            if (goodsReceipt.cosignee) {
                employeePromises.push(
                    dbSAPPS.Employee.findOne({
                        where: { id: goodsReceipt.cosignee },
                        attributes: ["id", "employee_name", "company_id"],
                        include: [
                            {
                                model: dbSAPPS.Company,
                                as: "company",
                                attributes: ["id", "display_name"],
                            },
                        ],
                    })
                );
            }

            const [shipper, cosignee] = await Promise.all(employeePromises);

            return {
                ...goodsReceipt.dataValues,
                shipper_name: shipper ? shipper.employee_name : null,
                cosignee_name: cosignee ? cosignee.employee_name : null,
                shipper_company_name: shipper ? shipper.company.display_name : null,
                cosignee_company_name: cosignee ? cosignee.company.display_name : null,
            };
        });

        const goodsReceiptsWithEmployeeNames = await Promise.all(goodsReceiptsPromises);

        return {
            goodsReceipts: goodsReceiptsWithEmployeeNames,
            success: true,
            message: "goods receipts loaded successfully!",
        };
    } catch (error) {
        const errorMessage = error.message || "Failed to load goods receipts!";
        return {
            success: false,
            message: errorMessage,
        };
    }
}

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

    try {
        const goodsReceipts = await dbSAPPS.GoodsReceipt.findAll({
            where: filterConditions,
            order: [["modified", "DESC"]],
        });

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

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

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

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

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

async function create(params) {
    const transaction = await dbSAPPS.sequelize.transaction();
    try {
        if (!params.material_request_name || !params.purchase_order_name || !params.item_code || !params.item_name)
            return {
                success: false,
                message: "material request name, purchase order name, item code, and item name are required!",
            };

        const existing = await dbSAPPS.GoodsReceipt.findOne({
            where: {
                material_request_name: params.material_request_name,
                purchase_order_name: params.purchase_order_name,
                item_code: params.item_code,
                item_name: params.item_name
            },
        });

        if (existing)
            return {
                success: false,
                message: `goods receipt with material request name "${params.material_request_name}", purchase order name "${params.purchase_order_name}", item code "${params.item_code}", and item name "${params.item_name}" is already taken.`,
            };

        if (!params.item_status || params.item_status === "") params.item_status = "On Delivery";
        if (!params.status || params.status === "") params.status = "In Process";

        await dbSAPPS.GoodsReceipt.create(params, { transaction });
        await transaction.commit();
        return {
            success: true,
            message: "goods receipt data has been successfully added!",
        };
    } catch (error) {
        await transaction.rollback();
        const errorMessage = error.message || "An error occurred during create goods receipt processing.";
        return {
            success: false,
            message: errorMessage,
        };
    }
}

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

        const existing = await dbSAPPS.GoodsReceipt.findOne({
            where: {
                material_request_name: params.material_request_name,
                purchase_order_name: params.purchase_order_name,
                item_code: params.item_code,
                item_name: params.item_name
            }
        });

        if (existing) {
            if (existing.id != params.id) {
                return {
                    success: false,
                    message: `goods receipt with material request name "${params.material_request_name}", purchase order name "${params.purchase_order_name}", item code "${params.item_code}", and item name "${params.item_name}" is already taken.`,
                };
            }
        }

        params.item_status = "Delivered";

        await goodsReceipt.update(params, { transaction });
        await transaction.commit();
        return {
            success: true,
            message: "Data goods receipt has been saved!",
        };
    } catch (error) {
        await transaction.rollback();
        const errorMessage = error.message || "Failed to update goods receipt data.";
        return {
            success: false,
            message: errorMessage,
        };
    }
}

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

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

async function completed(id, params) {
    try {
        const goodsReceipt = await dbSAPPS.GoodsReceipt.findByPk(id);
        if (!goodsReceipt)
            return {
                success: false,
                message: "goods receipt not found!",
            };

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

        await goodsReceipt.update(updateData);

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

async function _delete(id) {
    try {
        const goodsReceipt = await dbSAPPS.GoodsReceipt.findByPk(id);
        if (!goodsReceipt) return { success: false, message: "goods receipt not found!" };

        await goodsReceipt.destroy();
        return {
            success: true,
            message: "Goods receipt successfully deleted!",
        };
    } catch (error) {
        const errorMessage = error.message || "Failed to delete goods receipt.";
        return {
            success: false,
            message: errorMessage,
        };
    }
}

