const { Order, OrderDetails, Product } = require("../../models");
const { STATUS_CODE } = require("../../utils/utility");
const routeHandler = require("../../utils/routeHandler");
const { sendAppError } = require("../../utils/appError");
const fastcsv = require('fast-csv');
const path = require('path');
const fs = require('fs');

const bulkUpload = routeHandler(async (req, res, extras) => {
    const file = req.file;
    const { user_id } = req.auth;
    if (!file) {
        return sendAppError(extras, NO_FILE, STATUS_CODE.BAD_REQUEST);
    }
    const filePath = path.join(__dirname, '../../uploads', file.filename || `${Date.now()}_${file.originalname}`);
    if (file.buffer) {
        fs.writeFileSync(filePath, file.buffer);
    }

    const orderDetailsData = [];
    const errors = [];
    const stream = fs.createReadStream(filePath);
    try {
        const processingPromises = [];

        await new Promise((resolve, reject) => {
            fastcsv.parseStream(stream, { headers: true })
                .on('data', (row) => {
                    processingPromises.push(
                        (async () => {
                            const { rowRefId, rowOrderId, rowProductId, rowPrice, rowQuantity, rowAmount, rowDeteteStatus } = row;

                            if (!rowOrderId || !rowProductId || !rowPrice || !rowQuantity || !rowAmount || !rowDeteteStatus) {
                                errors.push(`required for row: ${rowRefId}`);
                            } else {
                                try {
                                    const existingOrder = await Order.findOne({ where: { tbl_ref_id: rowOrderId }, paranoid: false, });
                                    const existingProduct = await Product.findOne({ where: { tbl_ref_id: rowProductId } });

                                    if (existingOrder && existingProduct) {
                                        orderDetailsData.push({
                                            tbl_ref_id: rowRefId,
                                            order_id: existingOrder.order_id,
                                            product_id: existingProduct.product_id,
                                            price: rowPrice,
                                            quantity: rowQuantity,
                                            amount: rowAmount,
                                            created_by: user_id,
                                            deleted_at: Number(rowDeteteStatus) === 0 ? new Date() : null,
                                            deleted_by: Number(rowDeteteStatus) === 0 ? user_id : null,
                                        });
                                    } else {
                                        errors.push(`Order or Product does not exist for row: ${rowRefId}`);
                                    }
                                } catch (dbError) {
                                    console.log(dbError);
                                    errors.push(`Database error in row: ${rowRefId}`);
                                }
                            }
                        })()
                    );
                })
                .on('end', async () => {
                    try {
                        await Promise.all(processingPromises);
                        resolve();
                    } catch (err) {
                        reject(err);
                    }
                })
                .on('error', (error) => reject(error));
        });

        if (errors.length > 0) {
            return sendAppError(extras, errors.join(', '), STATUS_CODE.BAD_REQUEST);
        }

        const BATCH_SIZE = 1000;
        await extras.transaction.begin();
        try {
            for (let i = 0; i < orderDetailsData.length; i += BATCH_SIZE) {
                const batch = orderDetailsData.slice(i, i + BATCH_SIZE);
                await OrderDetails.bulkCreate(batch, { transaction: extras.transaction });
            }
            await extras.transaction.commit();
            return res.sendRes(null, { message: 'Order details data created successfully', status: STATUS_CODE.OK });
        } catch (error) {
            await extras.transaction.rollback();
            return sendAppError(extras, 'Failed to create order details data', STATUS_CODE.INTERNAL_SERVER_ERROR);
        }
    } catch (error) {
        return sendAppError(extras, 'Error processing file', STATUS_CODE.INTERNAL_SERVER_ERROR);
    } finally {
        fs.unlinkSync(filePath);
    }
});

module.exports = {
    bulkUpload
};
