const { Op } = require('sequelize');
const db = require('../models');
const asyncHandler = require('../middlewares/asyncHandler');
const { sendResponse, sendError } = require('../utils/response');
const { getPagination, getPagingData } = require('../utils/pagination');
const { generateNextNumber } = require('../services/numberFormatService');

const getUserId = (req) => req.user?.userId || req.user?.id || null;
const DC_EDITABLE_STATUSES = ['DRAFT', 'APPROVED'];
const toNum = (v) => {
  const n = parseFloat(v);
  return Number.isFinite(n) ? n : 0;
};
const composeAddress = (addr) => [
  addr?.address_line1,
  addr?.address_line2,
  addr?.city?.city_name,
  addr?.state?.state_name,
  addr?.country?.country_name,
  addr?.pincode
]
  .map((x) => String(x || '').trim())
  .filter(Boolean)
  .join(', ');

const generateGeneralDCNumber = async (companyId, fiscalYearId = null, transaction = null) => {
  try {
    return await generateNextNumber(companyId, 'GENERAL_DC', fiscalYearId, transaction);
  } catch (_) {
    const year = new Date().getFullYear();
    const prefix = `GDC${year}`;
    const last = await db.GeneralDC.findOne({
      where: { company_id: companyId, dc_number: { [Op.like]: `${prefix}%` } },
      order: [['dc_number', 'DESC']],
      ...(transaction ? { transaction } : {})
    });
    const next = (parseInt(String(last?.dc_number || '').slice(-4), 10) || 0) + 1;
    return `${prefix}${String(next).padStart(4, '0')}`;
  }
};

const generateGeneralReceiptNumber = async (companyId, fiscalYearId = null, transaction = null) => {
  try {
    return await generateNextNumber(companyId, 'GENERAL_RECEIPT', fiscalYearId, transaction);
  } catch (_) {
    const year = new Date().getFullYear();
    const prefix = `GRC${year}`;
    const last = await db.GeneralReceipt.findOne({
      where: { company_id: companyId, receipt_number: { [Op.like]: `${prefix}%` } },
      order: [['receipt_number', 'DESC']],
      ...(transaction ? { transaction } : {})
    });
    const next = (parseInt(String(last?.receipt_number || '').slice(-4), 10) || 0) + 1;
    return `${prefix}${String(next).padStart(4, '0')}`;
  }
};

exports.getAllDC = asyncHandler(async (req, res) => {
  const { page = 1, limit = 25, search, companyId, plantId, fiscalYearId, machineId, vendorId, status } = req.query;
  const { limit: limitNum, offset } = getPagination(page, limit);
  const where = {};

  if (companyId) where.company_id = companyId;
  else if (req.user && !req.user.isSuperAdmin) where.company_id = req.user.companyId;
  if (plantId) where.plant_id = plantId;
  if (fiscalYearId) where.fiscal_year_id = fiscalYearId;
  if (machineId) where.machine_id = machineId;
  if (vendorId) where.vendor_id = vendorId;
  if (status) where.status = status;
  if (search) {
    where[Op.or] = [
      { dc_number: { [Op.like]: `%${search}%` } },
      { reference_no: { [Op.like]: `%${search}%` } }
    ];
  }

  const rows = await db.GeneralDC.findAndCountAll({
    where,
    include: [
      { model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description', 'location'] },
      { model: db.BusinessPartner, as: 'vendor', attributes: ['id', 'bp_number', 'name', 'legal_name'] },
      {
        model: db.GeneralDCItem,
        as: 'items',
        required: false,
        attributes: ['id', 'machine_id', 'machine_work'],
        include: [{ model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description'] }]
      }
    ],
    distinct: true,
    limit: limitNum,
    offset,
    order: [['dc_date', 'DESC'], ['id', 'DESC']]
  });

  sendResponse(res, 200, true, 'General DC list retrieved successfully', getPagingData(rows, page, limitNum));
});

exports.getDCById = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const dc = await db.GeneralDC.findByPk(id, {
    include: [
      { model: db.Company, as: 'company' },
      { model: db.Plant, as: 'plant' },
      { model: db.FiscalYear, as: 'fiscalYear' },
      { model: db.Machine, as: 'machine' },
      { model: db.BusinessPartner, as: 'vendor' },
      {
        model: db.GeneralDCItem,
        as: 'items',
        include: [
          { model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description'] },
          { model: db.StorageLocation, as: 'storageLocation', attributes: ['id', 'storage_location_code', 'description'] }
        ]
      }
    ],
    order: [[{ model: db.GeneralDCItem, as: 'items' }, 'line_number', 'ASC']]
  });
  if (!dc) return sendError(res, 'General DC not found', 404);
  sendResponse(res, 200, true, 'General DC retrieved successfully', dc);
});

exports.createDC = asyncHandler(async (req, res) => {
  const userId = getUserId(req);
  const companyId = req.user?.companyId || req.body.company_id;
  const data = req.body || {};
  if (!companyId) return sendError(res, 'Company ID is required', 400);
  if (!data.plant_id || !data.fiscal_year_id || !data.vendor_id) {
    return sendError(res, 'Plant, Fiscal Year and Vendor are required', 400);
  }
  if (!Array.isArray(data.items) || data.items.length === 0) {
    return sendError(res, 'At least one machine work item is required', 400);
  }

  const transaction = await db.sequelize.transaction();
  try {
    const dcNumber = data.dc_number || await generateGeneralDCNumber(companyId, data.fiscal_year_id, transaction);
    const firstLineMachineId = data.items.find((it) => it?.machine_id)?.machine_id || data.machine_id || null;
    if (!firstLineMachineId) throw new Error('At least one line must have machine selected');
    const dc = await db.GeneralDC.create({
      company_id: companyId,
      plant_id: data.plant_id,
      fiscal_year_id: data.fiscal_year_id,
      dc_number: dcNumber,
      dc_date: data.dc_date || new Date().toISOString().slice(0, 10),
      machine_id: firstLineMachineId,
      vendor_id: data.vendor_id,
      operation_type: data.operation_type || null,
      reference_no: data.reference_no || null,
      delivery_address: data.delivery_address || null,
      transport_name: data.transport_name || null,
      vehicle_no: data.vehicle_no || null,
      driver_name: data.driver_name || null,
      driver_phone: data.driver_phone || null,
      eway_bill_no: data.eway_bill_no || null,
      remarks: data.remarks || null,
      status: 'DRAFT',
      created_by: userId,
      updated_by: userId
    }, { transaction });

    let totalSentQty = 0;
    let totalAmount = 0;
    for (let i = 0; i < data.items.length; i += 1) {
      const item = data.items[i];
      const sentQty = toNum(item.sent_quantity || item.quantity);
      if (!(sentQty > 0)) throw new Error(`Sent quantity must be greater than 0 at line ${i + 1}`);
      if (!item.machine_id) throw new Error(`Machine is required at line ${i + 1}`);
      if (!String(item.machine_work || '').trim()) {
        throw new Error(`Machine work is required at line ${i + 1}`);
      }
      const unitPrice = toNum(item.unit_price);
      const lineTotal = sentQty * unitPrice;

      await db.GeneralDCItem.create({
        general_dc_id: dc.id,
        line_number: i + 1,
        machine_id: item.machine_id,
        machine_work: String(item.machine_work || '').trim() || null,
        sent_quantity: sentQty,
        unit_price: unitPrice,
        line_total: lineTotal,
        received_quantity: 0,
        rejection_quantity: 0,
        storage_location_id: item.storage_location_id || null,
        remarks: item.remarks || null
      }, { transaction });

      totalSentQty += sentQty;
      totalAmount += lineTotal;
    }

    await dc.update({ total_sent_qty: totalSentQty, total_amount: totalAmount }, { transaction });
    await transaction.commit();

    const createdDC = await db.GeneralDC.findByPk(dc.id, {
      include: [
        { model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description', 'location'] },
        { model: db.BusinessPartner, as: 'vendor', attributes: ['id', 'bp_number', 'name', 'legal_name'] },
        { model: db.GeneralDCItem, as: 'items' }
      ]
    });
    sendResponse(res, 201, true, 'General DC created successfully', createdDC);
  } catch (error) {
    await transaction.rollback();
    sendError(res, error.message || 'Failed to create General DC', 400);
  }
});

exports.updateDC = asyncHandler(async (req, res) => {
  const userId = getUserId(req);
  const { id } = req.params;
  const data = req.body || {};

  const transaction = await db.sequelize.transaction();
  try {
    const dc = await db.GeneralDC.findByPk(id, {
      include: [{ model: db.GeneralDCItem, as: 'items' }],
      transaction,
      lock: transaction.LOCK.UPDATE
    });
    if (!dc) throw new Error('General DC not found');
    if (!DC_EDITABLE_STATUSES.includes(dc.status)) {
      throw new Error(`Cannot edit General DC with status ${dc.status}`);
    }
    if (!Array.isArray(data.items) || data.items.length === 0) {
      throw new Error('At least one machine work item is required');
    }

    await dc.update({
      dc_date: data.dc_date || dc.dc_date,
      machine_id: data.items.find((it) => it?.machine_id)?.machine_id || data.machine_id || dc.machine_id,
      vendor_id: data.vendor_id || dc.vendor_id,
      operation_type: data.operation_type || dc.operation_type,
      reference_no: data.reference_no || null,
      delivery_address: data.delivery_address ?? dc.delivery_address,
      transport_name: data.transport_name ?? dc.transport_name,
      vehicle_no: data.vehicle_no ?? dc.vehicle_no,
      driver_name: data.driver_name ?? dc.driver_name,
      driver_phone: data.driver_phone ?? dc.driver_phone,
      eway_bill_no: data.eway_bill_no ?? dc.eway_bill_no,
      remarks: data.remarks || null,
      updated_by: userId
    }, { transaction });

    await db.GeneralDCItem.destroy({ where: { general_dc_id: dc.id }, transaction });

    let totalSentQty = 0;
    let totalAmount = 0;
    for (let i = 0; i < data.items.length; i += 1) {
      const item = data.items[i];
      const sentQty = toNum(item.sent_quantity || item.quantity);
      if (!(sentQty > 0)) throw new Error(`Sent quantity must be greater than 0 at line ${i + 1}`);
      if (!item.machine_id) throw new Error(`Machine is required at line ${i + 1}`);
      if (!String(item.machine_work || '').trim()) {
        throw new Error(`Machine work is required at line ${i + 1}`);
      }
      const unitPrice = toNum(item.unit_price);
      const lineTotal = sentQty * unitPrice;

      await db.GeneralDCItem.create({
        general_dc_id: dc.id,
        line_number: i + 1,
        machine_id: item.machine_id,
        machine_work: String(item.machine_work || '').trim() || null,
        sent_quantity: sentQty,
        unit_price: unitPrice,
        line_total: lineTotal,
        received_quantity: 0,
        rejection_quantity: 0,
        storage_location_id: item.storage_location_id || null,
        remarks: item.remarks || null
      }, { transaction });

      totalSentQty += sentQty;
      totalAmount += lineTotal;
    }

    await dc.update({ total_sent_qty: totalSentQty, total_amount: totalAmount }, { transaction });
    await transaction.commit();

    const updated = await db.GeneralDC.findByPk(dc.id, {
      include: [
        { model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description', 'location'] },
        { model: db.BusinessPartner, as: 'vendor', attributes: ['id', 'bp_number', 'name', 'legal_name'] },
        { model: db.GeneralDCItem, as: 'items' }
      ]
    });
    sendResponse(res, 200, true, 'General DC updated successfully', updated);
  } catch (error) {
    await transaction.rollback();
    sendError(res, error.message || 'Failed to update General DC', 400);
  }
});

exports.approveDC = asyncHandler(async (req, res) => {
  const userId = getUserId(req);
  const { id } = req.params;
  const dc = await db.GeneralDC.findByPk(id);
  if (!dc) return sendError(res, 'General DC not found', 404);
  if (dc.status !== 'DRAFT') return sendError(res, `Only DRAFT DC can be approved. Current: ${dc.status}`, 400);

  await dc.update({ status: 'APPROVED', updated_by: userId });
  sendResponse(res, 200, true, 'General DC approved successfully', dc);
});

exports.sendDC = asyncHandler(async (req, res) => {
  const userId = getUserId(req);
  const { id } = req.params;
  const transaction = await db.sequelize.transaction();
  try {
    const dc = await db.GeneralDC.findByPk(id, {
      include: [{ model: db.GeneralDCItem, as: 'items' }],
      transaction,
      lock: transaction.LOCK.UPDATE
    });
    if (!dc) throw new Error('General DC not found');
    if (dc.status !== 'APPROVED') throw new Error(`Only APPROVED DC can be sent. Current: ${dc.status}`);
    if (!Array.isArray(dc.items) || dc.items.length === 0) throw new Error('No items found to send');

    for (let i = 0; i < dc.items.length; i += 1) {
      const item = dc.items[i];
      const sentQty = toNum(item.sent_quantity);
      if (!(sentQty > 0)) {
        throw new Error(`Sent quantity must be greater than 0 at line ${item.line_number || (i + 1)}`);
      }

      // General service DC is for machine service workflow; no stock movement entry.
    }

    await dc.update({ status: 'SENT', updated_by: userId }, { transaction });
    await transaction.commit();
    sendResponse(res, 200, true, 'General DC sent successfully', dc);
  } catch (error) {
    await transaction.rollback();
    sendError(res, error.message || 'Failed to send General DC', 400);
  }
});

exports.getDCPendingItems = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const dc = await db.GeneralDC.findByPk(id, {
    include: [
      {
        model: db.GeneralDCItem,
        as: 'items',
        include: [
          { model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description'] },
          { model: db.StorageLocation, as: 'storageLocation', attributes: ['id', 'storage_location_code', 'description'] }
        ]
      },
      { model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description', 'location'] }
    ],
    order: [[{ model: db.GeneralDCItem, as: 'items' }, 'line_number', 'ASC']]
  });
  if (!dc) return sendError(res, 'General DC not found', 404);

  const pendingItems = (dc.items || []).map((item) => {
    const sent = toNum(item.sent_quantity);
    const received = toNum(item.received_quantity);
    const rejected = toNum(item.rejection_quantity);
    const pending = Math.max(sent - received - rejected, 0);
    return { ...item.toJSON(), pending_quantity: pending };
  }).filter((item) => item.pending_quantity > 0);

  sendResponse(res, 200, true, 'General DC pending items retrieved successfully', {
    general_dc_id: dc.id,
    dc_number: dc.dc_number,
    dc_date: dc.dc_date,
    machine: dc.machine,
    operation_type: dc.operation_type,
    items: pendingItems
  });
});

exports.getMachineDetails = asyncHandler(async (req, res) => {
  const machineId = parseInt(req.params.machineId, 10);
  if (!Number.isFinite(machineId) || machineId <= 0) return sendError(res, 'Valid machineId is required', 400);
  const machine = await db.Machine.findByPk(machineId, {
    attributes: ['id', 'machine_code', 'machine_description', 'location', 'plant_id', 'status']
  });
  if (!machine) return sendError(res, 'Machine not found', 404);
  sendResponse(res, 200, true, 'Machine details retrieved successfully', {
    machine_id: machine.id,
    machine_code: machine.machine_code,
    machine_name: machine.machine_description,
    delivery_address: machine.location || ''
  });
});

exports.getVendorAddress = asyncHandler(async (req, res) => {
  const vendorId = parseInt(req.params.vendorId, 10);
  if (!Number.isFinite(vendorId) || vendorId <= 0) return sendError(res, 'Valid vendorId is required', 400);

  const vendor = await db.BusinessPartner.findByPk(vendorId, {
    attributes: ['id', 'bp_number', 'name', 'legal_name'],
    include: [
      {
        model: db.BPAddress,
        as: 'addresses',
        required: false,
        include: [
          { model: db.City, as: 'city', attributes: ['id', 'city_name'], required: false },
          { model: db.State, as: 'state', attributes: ['id', 'state_name'], required: false },
          { model: db.Country, as: 'country', attributes: ['id', 'country_name'], required: false }
        ]
      }
    ]
  });
  if (!vendor) return sendError(res, 'Vendor not found', 404);

  const active = (vendor.addresses || []).filter((a) => String(a.status || 'ACTIVE').toUpperCase() === 'ACTIVE');
  const list = active.length ? active : (vendor.addresses || []);
  const preferred = list.find((a) => a.is_default)
    || list.find((a) => String(a.address_type || '').toUpperCase() === 'SHIPPING')
    || list.find((a) => String(a.address_type || '').toUpperCase() === 'BILLING')
    || list[0]
    || null;

  sendResponse(res, 200, true, 'Vendor address retrieved successfully', {
    vendor_id: vendor.id,
    vendor_name: vendor.name || vendor.legal_name || '',
    address: composeAddress(preferred),
    address_object: preferred
  });
});

exports.getAllReceipts = asyncHandler(async (req, res) => {
  const { page = 1, limit = 25, search, companyId, plantId, fiscalYearId, machineId, vendorId } = req.query;
  const { limit: limitNum, offset } = getPagination(page, limit);
  const where = {};

  if (companyId) where.company_id = companyId;
  else if (req.user && !req.user.isSuperAdmin) where.company_id = req.user.companyId;
  if (plantId) where.plant_id = plantId;
  if (fiscalYearId) where.fiscal_year_id = fiscalYearId;
  if (machineId) where.machine_id = machineId;
  if (vendorId) where.vendor_id = vendorId;
  if (search) where.receipt_number = { [Op.like]: `%${search}%` };

  const rows = await db.GeneralReceipt.findAndCountAll({
    where,
    include: [
      { model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description'] },
      { model: db.BusinessPartner, as: 'vendor', attributes: ['id', 'bp_number', 'name', 'legal_name'] },
      { model: db.GeneralDC, as: 'generalDC', attributes: ['id', 'dc_number', 'dc_date'] },
      { model: db.GeneralReceiptItem, as: 'items', required: false, attributes: ['id'] }
    ],
    distinct: true,
    limit: limitNum,
    offset,
    order: [['receipt_date', 'DESC'], ['id', 'DESC']]
  });

  sendResponse(res, 200, true, 'General Receipts retrieved successfully', getPagingData(rows, page, limitNum));
});

exports.getReceiptById = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const receipt = await db.GeneralReceipt.findByPk(id, {
    include: [
      { model: db.Company, as: 'company' },
      { model: db.Plant, as: 'plant' },
      { model: db.FiscalYear, as: 'fiscalYear' },
      { model: db.Machine, as: 'machine' },
      { model: db.BusinessPartner, as: 'vendor' },
      { model: db.GeneralDC, as: 'generalDC', attributes: ['id', 'dc_number', 'dc_date', 'operation_type', 'reference_no'] },
      {
        model: db.GeneralReceiptItem,
        as: 'items',
        include: [
          { model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description'] },
          { model: db.StorageLocation, as: 'storageLocation', attributes: ['id', 'storage_location_code', 'description'] }
        ]
      }
    ],
    order: [[{ model: db.GeneralReceiptItem, as: 'items' }, 'line_number', 'ASC']]
  });
  if (!receipt) return sendError(res, 'General Receipt not found', 404);
  sendResponse(res, 200, true, 'General Receipt retrieved successfully', receipt);
});

exports.createReceipt = asyncHandler(async (req, res) => {
  const userId = getUserId(req);
  const companyId = req.user?.companyId || req.body.company_id;
  const data = req.body || {};
  if (!companyId) return sendError(res, 'Company ID is required', 400);
  if (!data.plant_id || !data.fiscal_year_id || !data.general_dc_id || !Array.isArray(data.items) || data.items.length === 0) {
    return sendError(res, 'Plant, Fiscal Year, General DC and receipt items are required', 400);
  }

  const transaction = await db.sequelize.transaction();
  try {
    const dc = await db.GeneralDC.findByPk(data.general_dc_id, {
      include: [{ model: db.GeneralDCItem, as: 'items' }],
      transaction,
      lock: transaction.LOCK.UPDATE
    });
    if (!dc) throw new Error('Reference General DC not found');
    if (!['SENT', 'PARTIALLY_RECEIVED'].includes(dc.status)) {
      throw new Error(`Cannot receive against General DC with status ${dc.status}. Only SENT or PARTIALLY_RECEIVED is allowed`);
    }
    if (data.machine_id && String(data.machine_id) !== String(dc.machine_id)) {
      throw new Error('Machine does not match with selected General DC');
    }
    if (data.vendor_id && String(data.vendor_id) !== String(dc.vendor_id)) {
      throw new Error('Vendor does not match with selected General DC');
    }

    const receiptNumber = data.receipt_number || await generateGeneralReceiptNumber(companyId, data.fiscal_year_id, transaction);
    const receipt = await db.GeneralReceipt.create({
      company_id: companyId,
      plant_id: data.plant_id,
      fiscal_year_id: data.fiscal_year_id,
      receipt_number: receiptNumber,
      receipt_date: data.receipt_date || new Date().toISOString().slice(0, 10),
      machine_id: dc.machine_id,
      vendor_id: dc.vendor_id || null,
      general_dc_id: dc.id,
      remarks: data.remarks || null,
      status: 'POSTED',
      created_by: userId,
      updated_by: userId
    }, { transaction });

    let totalReceived = 0;
    let totalRejected = 0;
    let totalAmount = 0;
    const dcItemsById = new Map((dc.items || []).map((item) => [String(item.id), item]));
    for (let i = 0; i < data.items.length; i += 1) {
      const rItem = data.items[i];
      const dcItem = dcItemsById.get(String(rItem.general_dc_item_id));
      if (!dcItem) throw new Error(`Invalid DC item at line ${i + 1}`);

      const sent = toNum(dcItem.sent_quantity);
      const alreadyReceived = toNum(dcItem.received_quantity);
      const alreadyRejected = toNum(dcItem.rejection_quantity);
      const remaining = sent - alreadyReceived - alreadyRejected;

      const receivedQty = toNum(rItem.received_quantity);
      const rejectedQty = toNum(rItem.rejection_quantity);
      if (receivedQty < 0 || rejectedQty < 0) {
        throw new Error(`Received/Rejection quantity cannot be negative at line ${i + 1}`);
      }
      if (!(receivedQty > 0 || rejectedQty > 0)) {
        throw new Error(`Received or rejection quantity is required at line ${i + 1}`);
      }
      if (receivedQty + rejectedQty > remaining + 1e-9) {
        throw new Error(`Line ${i + 1} exceeds pending quantity. Pending: ${remaining.toFixed(3)}`);
      }

      const unitPrice = toNum(dcItem.unit_price);
      const lineTotal = receivedQty * unitPrice;

      await db.GeneralReceiptItem.create({
        general_receipt_id: receipt.id,
        general_dc_item_id: dcItem.id,
        line_number: i + 1,
        machine_id: dcItem.machine_id || null,
        machine_work: String(rItem.machine_work || dcItem.machine_work || '').trim() || null,
        sent_quantity: sent,
        unit_price: unitPrice,
        line_total: lineTotal,
        received_quantity: receivedQty,
        rejection_quantity: rejectedQty,
        storage_location_id: rItem.storage_location_id || dcItem.storage_location_id || null,
        remarks: rItem.remarks || null
      }, { transaction });

      // General service receipt is for machine service workflow; no stock movement entry.

      await dcItem.update({
        received_quantity: alreadyReceived + receivedQty,
        rejection_quantity: alreadyRejected + rejectedQty
      }, { transaction });

      totalReceived += receivedQty;
      totalRejected += rejectedQty;
      totalAmount += lineTotal;
    }

    await receipt.update({
      total_received_qty: totalReceived,
      total_rejection_qty: totalRejected,
      total_amount: totalAmount
    }, { transaction });

    const refreshedItems = await db.GeneralDCItem.findAll({
      where: { general_dc_id: dc.id },
      transaction
    });
    const sentTotal = refreshedItems.reduce((sum, item) => sum + toNum(item.sent_quantity), 0);
    const recTotal = refreshedItems.reduce((sum, item) => sum + toNum(item.received_quantity), 0);
    const rejTotal = refreshedItems.reduce((sum, item) => sum + toNum(item.rejection_quantity), 0);
    const isClosed = sentTotal <= (recTotal + rejTotal + 1e-9);

    await dc.update({
      total_sent_qty: sentTotal,
      total_received_qty: recTotal,
      status: isClosed ? 'CLOSED' : 'PARTIALLY_RECEIVED',
      updated_by: userId
    }, { transaction });

    await transaction.commit();

    const createdReceipt = await db.GeneralReceipt.findByPk(receipt.id, {
      include: [
        { model: db.Machine, as: 'machine', attributes: ['id', 'machine_code', 'machine_description'] },
        { model: db.BusinessPartner, as: 'vendor', attributes: ['id', 'bp_number', 'name', 'legal_name'] },
        { model: db.GeneralDC, as: 'generalDC', attributes: ['id', 'dc_number', 'status', 'operation_type'] },
        { model: db.GeneralReceiptItem, as: 'items' }
      ]
    });

    sendResponse(res, 201, true, 'General Receipt created successfully', createdReceipt);
  } catch (error) {
    await transaction.rollback();
    sendError(res, error.message || 'Failed to create General Receipt', 400);
  }
});
