/**
 * Label Printing Controllers
 * Request handlers for label printing operations
 */

// Import label printing service
const labelPrintingService = require('../services');
// Import async handler wrapper
const asyncHandler = require('../../../middlewares/asyncHandler');
// Import response helpers
const { success: successResponse } = require('../../../utils/response');
// Import logger
const logger = require('../../../utils/logger');

/**
 * Print label for inventory item
 * Prints a label for a specific inventory item (FG product with UUID)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const printInventoryItemLabel = asyncHandler(async (req, res) => {
  // Extract inventory item ID from request params
  const { id } = req.params;
  // Extract printer configuration from request body
  const printerConfig = req.body.printer || {};
  
  // Print label
  const result = await labelPrintingService.printInventoryItemLabel(
    parseInt(id),
    printerConfig
  );
  
  // Log label printing
  logger.info('Inventory item label printed via API', {
    inventoryItemId: id,
    printerMethod: result.printResult?.method,
  });
  
  // Return success response
  return successResponse(res, result, 'Label printed successfully');
});

/**
 * Print label for product
 * Generates and optionally prints a label template for a product
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const printProductLabel = asyncHandler(async (req, res) => {
  // Extract product ID from request params
  const { id } = req.params;
  // Extract printer configuration and sample UID from request body
  const { printer, sampleUID } = req.body;
  
  // Print/generate label
  const result = await labelPrintingService.printProductLabel(
    parseInt(id),
    printer || null,
    sampleUID || null
  );
  
  // Log label generation
  logger.info('Product label generated via API', {
    productId: id,
    printed: !!result.printResult,
  });
  
  // Return success response
  return successResponse(res, result, result.printResult ? 'Label printed successfully' : 'Label template generated successfully');
});

/**
 * Generate label preview
 * Generates a preview of the label with QR code (for UI display)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const generateLabelPreview = asyncHandler(async (req, res) => {
  // Extract query parameters
  const { inventory_item_id, product_id, uid } = req.query;
  
  // Generate preview
  const result = await labelPrintingService.generateLabelPreview(
    inventory_item_id ? parseInt(inventory_item_id) : null,
    product_id ? parseInt(product_id) : null,
    uid || null
  );
  
  // Log preview generation
  logger.info('Label preview generated via API', {
    inventoryItemId: inventory_item_id,
    productId: product_id,
  });
  
  // Return success response
  return successResponse(res, result, 'Label preview generated successfully');
});

/**
 * Get ZPL for inventory item (client-side printing)
 * Returns ZPL data for client-side printing (does not print server-side)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const getInventoryItemLabelZPL = asyncHandler(async (req, res) => {
  // Extract inventory item ID from request params
  const { id } = req.params;
  // Extract DPI and label dimensions from query params (optional)
  const { dpi, labelLength, labelWidth } = req.query;
  
  // Build options object for ZPL generation
  const options = {};
  if (dpi) options.dpi = parseInt(dpi);
  if (labelLength) options.labelLength = parseFloat(labelLength);
  if (labelWidth) options.labelWidth = parseFloat(labelWidth);
  
  // Get inventory item with product to generate ZPL
  const result = await labelPrintingService.generateLabelPreview(parseInt(id), null, null, options);
  
  // Get ZPL data (result should have zplData)
  if (!result.zplData) {
    // If no ZPL in preview result, generate it with options
    const zplData = await labelPrintingService.generateZPLTemplate({
      productName: result.productName || 'Product',
      uid: result.uid,
      qrData: result.uid,
    }, options);
    result.zplData = zplData;
  }
  
  // Log ZPL generation
  logger.info('ZPL generated for inventory item via API', {
    inventoryItemId: id,
    productName: result.productName,
    uid: result.uid,
    dpi: options.dpi || 203,
  });
  
  // Return ZPL data
  return successResponse(res, { 
    zplData: result.zplData,
    productName: result.productName,
    uid: result.uid,
  }, 'ZPL data generated successfully');
});

/**
 * Get ZPL for product (client-side printing)
 * Returns ZPL data for client-side printing (does not print server-side)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const getProductLabelZPL = asyncHandler(async (req, res) => {
  // Extract product ID from request params
  const { id } = req.params;
  // Extract sample UID, DPI, and label dimensions from query
  const { uid, dpi, labelLength, labelWidth } = req.query;
  
  // Build options object for ZPL generation
  const options = {};
  if (dpi) options.dpi = parseInt(dpi);
  if (labelLength) options.labelLength = parseFloat(labelLength);
  if (labelWidth) options.labelWidth = parseFloat(labelWidth);
  
  // Generate preview with ZPL
  const result = await labelPrintingService.generateLabelPreview(null, parseInt(id), uid || null, options);
  
  // Get ZPL data
  if (!result.zplData) {
    // If no ZPL in preview result, generate it with options
    const zplData = await labelPrintingService.generateZPLTemplate({
      productName: result.productName || 'Product',
      uid: result.uid,
      qrData: result.uid,
    }, options);
    result.zplData = zplData;
  }
  
  // Log ZPL generation
  logger.info('ZPL generated for product via API', {
    productId: id,
    productName: result.productName,
    uid: result.uid,
    dpi: options.dpi || 203,
  });
  
  // Return ZPL data
  return successResponse(res, { 
    zplData: result.zplData,
    productName: result.productName,
    uid: result.uid,
  }, 'ZPL data generated successfully');
});

/**
 * Generate ZPL template
 * Generates ZPL template string for a label (without printing)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const generateZPLTemplate = asyncHandler(async (req, res) => {
  // Extract label data from request body
  const { productName, uid, qrData } = req.body;
  
  // Generate ZPL template
  const zplData = await labelPrintingService.generateZPLTemplate({
    productName,
    uid,
    qrData: qrData || uid,
  });
  
  // Log ZPL generation
  logger.info('ZPL template generated via API', {
    productName,
    uid,
  });
  
  // Return success response
  return successResponse(res, { zplData }, 'ZPL template generated successfully');
});

/**
 * Generate ZPL for a batch of inventory items (client-side/local printing)
 * Returns ZPL payloads for each inventory item ID provided.
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const generateBatchInventoryItemZPL = asyncHandler(async (req, res) => {
  const { inventory_item_ids, dpi, labelLength, labelWidth } = req.body || {};

  const ids = Array.isArray(inventory_item_ids)
    ? inventory_item_ids.map((id) => parseInt(id, 10)).filter((id) => !Number.isNaN(id))
    : [];

  if (!ids.length) {
    throw new Error('inventory_item_ids must be a non-empty array of IDs');
  }

  const options = {};
  if (dpi) options.dpi = parseInt(dpi, 10);
  if (labelLength) options.labelLength = parseFloat(labelLength);
  if (labelWidth) options.labelWidth = parseFloat(labelWidth);

  const batch = await labelPrintingService.generateBatchInventoryItemZPL(ids, options);

  logger.info('Batch ZPL generated via API', {
    count: batch.length,
  });

  return successResponse(
    res,
    { items: batch },
    'Batch ZPL data generated successfully',
  );
});

// Export controllers
module.exports = {
  printInventoryItemLabel, // Print label for inventory item (server-side)
  printProductLabel, // Print label for product (server-side)
  generateLabelPreview, // Generate label preview
  generateZPLTemplate, // Generate ZPL template
  getInventoryItemLabelZPL, // Get ZPL for inventory item (client-side)
  getProductLabelZPL, // Get ZPL for product (client-side)
  generateBatchInventoryItemZPL, // Generate ZPL for a batch of inventory items (client-side)
};
