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 generateRFQNumber = async (companyId) => {
  const today = new Date();
  const year = today.getFullYear();
  const prefix = `RFQ${year}`;
  
  const lastRFQ = await db.RequestForQuotation.findOne({
    where: {
      company_id: companyId,
      rfq_number: { [Op.like]: `${prefix}%` }
    },
    order: [['rfq_number', 'DESC']]
  });

  let sequence = 1;
  if (lastRFQ) {
    const lastSequence = parseInt(lastRFQ.rfq_number.slice(-4)) || 0;
    sequence = lastSequence + 1;
  }

  return `${prefix}${sequence.toString().padStart(4, '0')}`;
};

exports.getAll = asyncHandler(async (req, res) => {
  const { page = 1, limit = 25, search, status, companyId, plantId, fiscalYearId } = 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 (status) {
    where.status = status;
  }

  if (search) {
    where[Op.or] = [
      { rfq_number: { [Op.like]: `%${search}%` } }
    ];
  }

  const records = await db.RequestForQuotation.findAndCountAll({
    where,
    include: [
      { model: db.Company, as: 'company', attributes: ['id', 'code', 'name'] },
      { model: db.Plant, as: 'plant', attributes: ['id', 'code', 'name'] },
      { model: db.PurchaseRequisition, as: 'purchaseRequisition', attributes: ['id', 'pr_number'] }
    ],
    limit: limitNum,
    offset,
    order: [['rfq_date', 'DESC'], ['id', 'DESC']]
  });

  const response = getPagingData(records, page, limitNum);
  sendResponse(res, 200, true, 'Request for Quotations retrieved successfully', response);
});

exports.getById = asyncHandler(async (req, res) => {
  const { id } = req.params;

  const rfq = await db.RequestForQuotation.findByPk(id, {
    include: [
      { model: db.Company, as: 'company' },
      { model: db.Plant, as: 'plant' },
      { model: db.FiscalYear, as: 'fiscalYear' },
      { model: db.PurchaseRequisition, as: 'purchaseRequisition' },
      { model: db.Currency, as: 'currency' },
      {
        model: db.RequestForQuotationItem,
        as: 'items',
        include: [
          { model: db.Material, as: 'material' },
          { model: db.UOM, as: 'uom' },
          { model: db.BusinessPartner, as: 'vendor', attributes: ['id', 'bp_number', 'name'] }
        ],
        order: [['line_number', 'ASC']]
      }
    ]
  });

  if (!rfq) {
    return sendError(res, 'Request for Quotation not found', 404);
  }

  sendResponse(res, 200, true, 'Request for Quotation retrieved successfully', rfq);
});

exports.create = asyncHandler(async (req, res) => {
  const data = req.body;
  const userId = req.user?.userId || null;
  const companyId = req.user?.companyId;

  if (!companyId) {
    return sendError(res, 'Company ID is required', 400);
  }

  if (!data.plant_id || !data.fiscal_year_id) {
    return sendError(res, 'Plant ID and Fiscal Year ID are required', 400);
  }

  const transaction = await db.sequelize.transaction();

  try {
    if (!data.rfq_number) {
      data.rfq_number = await generateRFQNumber(companyId);
    }

    data.company_id = companyId;
    data.created_by = userId;
    data.updated_by = userId;

    const { items, ...rfqData } = data;
    
    let totalAmount = 0;
    if (items && Array.isArray(items)) {
      items.forEach(item => {
        totalAmount += parseFloat(item.estimated_amount || 0);
      });
    }
    rfqData.total_amount = totalAmount;

    const rfq = await db.RequestForQuotation.create(rfqData, { transaction });

    if (items && Array.isArray(items)) {
      const rfqItems = items.map((item, index) => ({
        rfq_id: rfq.id,
        line_number: item.item_number || index + 1,
        material_id: item.material_id,
        description: item.description,
        quantity: item.quantity,
        uom_id: item.uom_id,
        vendor_id: item.vendor_id || null,
        remarks: item.remarks
      }));

      await db.RequestForQuotationItem.bulkCreate(rfqItems, { transaction });
    }

    await transaction.commit();

    const createdRFQ = await db.RequestForQuotation.findByPk(rfq.id, {
      include: [
        { 
          model: db.RequestForQuotationItem, 
          as: 'items', 
          include: [
            { model: db.Material, as: 'material' }, 
            { model: db.UOM, as: 'uom' },
            { model: db.BusinessPartner, as: 'vendor', attributes: ['id', 'bp_number', 'name'] }
          ] 
        }
      ]
    });

    sendResponse(res, 201, true, 'Request for Quotation created successfully', createdRFQ);
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
});

exports.update = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const data = req.body;
  const userId = req.user?.userId || null;

  const rfq = await db.RequestForQuotation.findByPk(id);
  if (!rfq) {
    return sendError(res, 'Request for Quotation not found', 404);
  }

  if (rfq.status !== 'DRAFT') {
    return sendError(res, 'Only DRAFT Request for Quotations can be updated', 400);
  }

  const transaction = await db.sequelize.transaction();

  try {
    const { items, ...rfqData } = data;
    rfqData.updated_by = userId;

    let totalAmount = 0;
    if (items && Array.isArray(items)) {
      items.forEach(item => {
        totalAmount += parseFloat(item.estimated_amount || 0);
      });
    }
    rfqData.total_amount = totalAmount;

    await rfq.update(rfqData, { transaction });

    if (items && Array.isArray(items)) {
      await db.RequestForQuotationItem.destroy({ where: { rfq_id: rfq.id }, transaction });

      const rfqItems = items.map((item, index) => ({
        rfq_id: rfq.id,
        line_number: item.item_number || index + 1,
        material_id: item.material_id,
        description: item.description,
        quantity: item.quantity,
        uom_id: item.uom_id,
        vendor_id: item.vendor_id || null,
        remarks: item.remarks
      }));

      await db.RequestForQuotationItem.bulkCreate(rfqItems, { transaction });
    }

    await transaction.commit();

    const updatedRFQ = await db.RequestForQuotation.findByPk(rfq.id, {
      include: [
        { 
          model: db.RequestForQuotationItem, 
          as: 'items', 
          include: [
            { model: db.Material, as: 'material' }, 
            { model: db.UOM, as: 'uom' },
            { model: db.BusinessPartner, as: 'vendor', attributes: ['id', 'bp_number', 'name'] }
          ] 
        }
      ]
    });

    sendResponse(res, 200, true, 'Request for Quotation updated successfully', updatedRFQ);
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
});

exports.submit = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const userId = req.user?.userId || null;

  const rfq = await db.RequestForQuotation.findByPk(id);
  if (!rfq) {
    return sendError(res, 'Request for Quotation not found', 404);
  }

  if (rfq.status !== 'DRAFT') {
    return sendError(res, 'Only DRAFT Request for Quotations can be submitted', 400);
  }

  await rfq.update({
    status: 'SUBMITTED',
    submitted_at: new Date(),
    submitted_by: userId,
    updated_by: userId
  });

  sendResponse(res, 200, true, 'Request for Quotation submitted successfully', rfq);
});

exports.close = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const userId = req.user?.userId || null;

  const rfq = await db.RequestForQuotation.findByPk(id);
  if (!rfq) {
    return sendError(res, 'Request for Quotation not found', 404);
  }

  if (rfq.status !== 'SUBMITTED') {
    return sendError(res, 'Only SUBMITTED Request for Quotations can be closed', 400);
  }

  await rfq.update({
    status: 'CLOSED',
    closed_at: new Date(),
    closed_by: userId,
    updated_by: userId
  });

  sendResponse(res, 200, true, 'Request for Quotation closed successfully', rfq);
});

exports.delete = asyncHandler(async (req, res) => {
  const { id } = req.params;

  const rfq = await db.RequestForQuotation.findByPk(id);
  if (!rfq) {
    return sendError(res, 'Request for Quotation not found', 404);
  }

  if (rfq.status !== 'DRAFT') {
    return sendError(res, 'Only DRAFT Request for Quotations can be deleted', 400);
  }

  const transaction = await db.sequelize.transaction();

  try {
    await db.RequestForQuotationItem.destroy({ where: { rfq_id: id }, transaction });
    await rfq.destroy({ transaction });
    await transaction.commit();

    sendResponse(res, 200, true, 'Request for Quotation deleted successfully', null);
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
});

