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

/**
 * Create or update batch
 * POST /api/v1/inventory/batch
 */
exports.createOrUpdateBatch = asyncHandler(async (req, res) => {
  const batchData = req.body;
  const userId = req.user?.userId || null;

  const batch = await batchSerialTrackingService.createOrUpdateBatch(batchData, userId);

  sendResponse(res, 200, true, 'Batch created/updated successfully', batch);
});

/**
 * Get batch by batch number
 * GET /api/v1/inventory/batch
 */
exports.getBatch = asyncHandler(async (req, res) => {
  const { companyId, plantId, materialId, batchNumber } = req.query;
  const userCompanyId = req.user?.companyId;

  if (!materialId || !batchNumber) {
    return sendError(res, 'Material ID and Batch Number are required', 400);
  }

  const effectiveCompanyId = companyId || userCompanyId;
  if (!effectiveCompanyId || !plantId) {
    return sendError(res, 'Company ID and Plant ID are required', 400);
  }

  const batch = await batchSerialTrackingService.getBatch(
    effectiveCompanyId,
    plantId,
    materialId,
    batchNumber
  );

  if (!batch) {
    return sendError(res, 'Batch not found', 404);
  }

  sendResponse(res, 200, true, 'Batch retrieved successfully', batch);
});

/**
 * Get batches for a material
 * GET /api/v1/inventory/batch/material/:materialId
 */
exports.getBatchesForMaterial = asyncHandler(async (req, res) => {
  const { materialId } = req.params;
  const { companyId, plantId, status } = req.query;
  const userCompanyId = req.user?.companyId;

  const effectiveCompanyId = companyId || userCompanyId;
  if (!effectiveCompanyId || !plantId) {
    return sendError(res, 'Company ID and Plant ID are required', 400);
  }

  const batches = await batchSerialTrackingService.getBatchesForMaterial(
    effectiveCompanyId,
    plantId,
    materialId,
    status || null
  );

  sendResponse(res, 200, true, 'Batches retrieved successfully', batches);
});

/**
 * Get available batches for a material
 * GET /api/v1/inventory/batch/material/:materialId/available
 */
exports.getAvailableBatches = asyncHandler(async (req, res) => {
  const { materialId } = req.params;
  const { companyId, plantId, storageLocation } = req.query;
  const userCompanyId = req.user?.companyId;

  const effectiveCompanyId = companyId || userCompanyId;
  if (!effectiveCompanyId || !plantId) {
    return sendError(res, 'Company ID and Plant ID are required', 400);
  }

  const batches = await batchSerialTrackingService.getAvailableBatches(
    effectiveCompanyId,
    plantId,
    materialId,
    storageLocation || null
  );

  sendResponse(res, 200, true, 'Available batches retrieved successfully', batches);
});

/**
 * Get expired batches
 * GET /api/v1/inventory/batch/expired
 */
exports.getExpiredBatches = asyncHandler(async (req, res) => {
  const { companyId, plantId, beforeDate } = req.query;
  const userCompanyId = req.user?.companyId;

  const effectiveCompanyId = companyId || userCompanyId;
  if (!effectiveCompanyId) {
    return sendError(res, 'Company ID is required', 400);
  }

  const batches = await batchSerialTrackingService.getExpiredBatches(
    effectiveCompanyId,
    plantId || null,
    beforeDate ? new Date(beforeDate) : null
  );

  sendResponse(res, 200, true, 'Expired batches retrieved successfully', batches);
});

/**
 * Create or update serial number
 * POST /api/v1/inventory/serial
 */
exports.createOrUpdateSerial = asyncHandler(async (req, res) => {
  const serialData = req.body;
  const userId = req.user?.userId || null;

  const serial = await batchSerialTrackingService.createOrUpdateSerial(serialData, userId);

  sendResponse(res, 200, true, 'Serial number created/updated successfully', serial);
});

/**
 * Get serial number by serial number
 * GET /api/v1/inventory/serial/:serialNumber
 */
exports.getSerial = asyncHandler(async (req, res) => {
  const { serialNumber } = req.params;

  const serial = await batchSerialTrackingService.getSerial(serialNumber);

  if (!serial) {
    return sendError(res, 'Serial number not found', 404);
  }

  sendResponse(res, 200, true, 'Serial number retrieved successfully', serial);
});

/**
 * Get serial numbers for a material
 * GET /api/v1/inventory/serial/material/:materialId
 */
exports.getSerialsForMaterial = asyncHandler(async (req, res) => {
  const { materialId } = req.params;
  const { companyId, plantId, status } = req.query;
  const userCompanyId = req.user?.companyId;

  const effectiveCompanyId = companyId || userCompanyId;
  if (!effectiveCompanyId || !plantId) {
    return sendError(res, 'Company ID and Plant ID are required', 400);
  }

  const serials = await batchSerialTrackingService.getSerialsForMaterial(
    effectiveCompanyId,
    plantId,
    materialId,
    status || null
  );

  sendResponse(res, 200, true, 'Serial numbers retrieved successfully', serials);
});

/**
 * Get available serial numbers for a material
 * GET /api/v1/inventory/serial/material/:materialId/available
 */
exports.getAvailableSerials = asyncHandler(async (req, res) => {
  const { materialId } = req.params;
  const { companyId, plantId, storageLocation } = req.query;
  const userCompanyId = req.user?.companyId;

  const effectiveCompanyId = companyId || userCompanyId;
  if (!effectiveCompanyId || !plantId) {
    return sendError(res, 'Company ID and Plant ID are required', 400);
  }

  const serials = await batchSerialTrackingService.getAvailableSerials(
    effectiveCompanyId,
    plantId,
    materialId,
    storageLocation || null
  );

  sendResponse(res, 200, true, 'Available serial numbers retrieved successfully', serials);
});

/**
 * Get serial number traceability
 * GET /api/v1/inventory/serial/:serialNumber/traceability
 */
exports.getSerialTraceability = asyncHandler(async (req, res) => {
  const { serialNumber } = req.params;

  const traceability = await batchSerialTrackingService.getSerialTraceability(serialNumber);

  if (!traceability) {
    return sendError(res, 'Serial number not found', 404);
  }

  sendResponse(res, 200, true, 'Serial number traceability retrieved successfully', traceability);
});

/**
 * Update serial number status
 * PUT /api/v1/inventory/serial/:serialNumber/status
 */
exports.updateSerialStatus = asyncHandler(async (req, res) => {
  const { serialNumber } = req.params;
  const { status, referenceType, referenceId, referenceNumber } = req.body;
  const userId = req.user?.userId || null;

  if (!status) {
    return sendError(res, 'Status is required', 400);
  }

  const serial = await batchSerialTrackingService.updateSerialStatus(
    serialNumber,
    status,
    referenceType || null,
    referenceId || null,
    referenceNumber || null,
    userId
  );

  sendResponse(res, 200, true, 'Serial number status updated successfully', serial);
});

