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

const batchStatus = (s) => String(s || '').toUpperCase();

/**
 * Same logic as production order list: released batch qty (MRP) and balance still to release.
 */
async function enrichWithReleasedAndBalance(rows) {
  const items = (rows || []).map((r) => (r?.toJSON ? r.toJSON() : r));
  const poIds = items.map((row) => row.id).filter(Boolean);
  if (poIds.length === 0) return items;

  const batchRows = await db.ProductionOrderBatch.findAll({
    where: { production_order_id: { [Op.in]: poIds } },
    attributes: ['production_order_id', 'quantity', 'status'],
    raw: true,
  });
  const batchesByPoId = batchRows.reduce((acc, r) => {
    const pid = r.production_order_id;
    if (!acc.has(pid)) acc.set(pid, []);
    acc.get(pid).push(r);
    return acc;
  }, new Map());

  return items.map((row) => {
    const bList = batchesByPoId.get(row.id) || [];
    const orderQty = parseFloat(row.order_quantity || 0) || 0;
    const mrpReleased = bList
      .filter((b) => ['RELEASED', 'IN_PROGRESS'].includes(batchStatus(b.status)))
      .reduce((sum, b) => sum + (parseFloat(b.quantity || 0) || 0), 0);
    const committedRelease = bList
      .filter((b) => ['RELEASED', 'IN_PROGRESS', 'COMPLETED'].includes(batchStatus(b.status)))
      .reduce((sum, b) => sum + (parseFloat(b.quantity || 0) || 0), 0);

    let released_for_mrp_qty = mrpReleased;
    let balance_to_release_qty = Math.max(0, orderQty - committedRelease);

    if (!row.batch_planning_enabled && bList.length === 0) {
      if (['RELEASED', 'IN_PROGRESS', 'PARTIALLY_CONFIRMED', 'CONFIRMED', 'CLOSED'].includes(row.status)) {
        released_for_mrp_qty = orderQty;
        balance_to_release_qty = 0;
      } else {
        released_for_mrp_qty = 0;
        balance_to_release_qty = orderQty;
      }
    }

    return {
      ...row,
      released_for_mrp_qty: Number(released_for_mrp_qty.toFixed(3)),
      balance_to_release_qty: Number(balance_to_release_qty.toFixed(3)),
    };
  });
}

/**
 * Production Order Register Report
 *
 * Query params: companyId, plantId, status, search, dateFrom, dateTo, page, limit, export
 */
exports.getProductionOrderRegisterReport = asyncHandler(async (req, res) => {
  try {
    const {
      page = 1,
      limit = 25,
      export: exportFlag,
      search,
      status,
      companyId,
      plantId,
      dateFrom,
      dateTo,
    } = req.query;

    const isExport = exportFlag === 'true' || exportFlag === true || exportFlag === 1 || exportFlag === '1';
    const effectiveLimit = isExport ? 50000 : parseInt(limit, 10) || 25;
    const effectivePage = isExport ? 1 : parseInt(page, 10) || 1;
    const { limit: limitNum, offset } = getPagination(effectivePage, effectiveLimit);

    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 (status && status !== 'ALL') where.status = status;

    if (dateFrom || dateTo) {
      where.production_order_date = {};
      if (dateFrom) where.production_order_date[Op.gte] = dateFrom;
      if (dateTo) where.production_order_date[Op.lte] = dateTo;
    }

    if (search && String(search).trim()) {
      where.production_order_number = { [Op.like]: `%${String(search).trim()}%` };
    }

    const include = [
      { model: db.Company, as: 'company', attributes: ['id', 'code', 'name'], required: false },
      { model: db.Plant, as: 'plant', attributes: ['id', 'code', 'name'], required: false },
      { model: db.Material, as: 'finishedMaterial', attributes: ['id', 'material_number', 'description'], required: false },
      { model: db.BOMHeader, as: 'bom', attributes: ['id', 'bom_number'], required: false },
      { model: db.CustomerPO, as: 'customerPO', attributes: ['id', 'po_number', 'po_date'], required: false },
    ];

    const records = await db.ProductionOrder.findAndCountAll({
      where,
      include,
      order: [['production_order_date', 'DESC'], ['production_order_number', 'DESC'], ['id', 'DESC']],
      limit: limitNum,
      offset,
      distinct: true,
      subQuery: false,
    });

    const enriched = await enrichWithReleasedAndBalance(records.rows || []);
    const response = getPagingData({ count: records.count || 0, rows: enriched }, effectivePage, limitNum);

    return sendResponse(res, 200, true, 'Production Order Register generated successfully', response);
  } catch (error) {
    console.error('Production Order Register Report error:', error);
    return sendError(res, error.message || 'Failed to generate Production Order Register', 500);
  }
});
