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

/**
 * Get production schedule for a date range
 * GET /api/v1/production/schedule
 */
exports.getSchedule = asyncHandler(async (req, res) => {
  const { companyId, plantId, startDate, endDate, workCenterId } = req.query;
  const userCompanyId = req.user?.companyId;

  if (!startDate || !endDate) {
    return sendError(res, 'Start date and end date are required', 400);
  }

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

  const schedules = await productionSchedulingService.getProductionSchedule(
    effectiveCompanyId,
    plantId || null,
    new Date(startDate),
    new Date(endDate),
    workCenterId || null
  );

  sendResponse(res, 200, true, 'Production schedule retrieved successfully', schedules);
});

/**
 * Forward schedule a Production Order
 * POST /api/v1/production/schedule/forward/:productionOrderId
 */
exports.forwardSchedule = asyncHandler(async (req, res) => {
  const { productionOrderId } = req.params;
  const { startDate } = req.body;
  const userId = req.user?.userId || null;

  if (!startDate) {
    return sendError(res, 'Start date is required', 400);
  }

  const productionOrder = await db.ProductionOrder.findByPk(productionOrderId, {
    include: [
      { model: db.Routing, as: 'routing' }
    ]
  });

  if (!productionOrder) {
    return sendError(res, 'Production Order not found', 404);
  }

  const schedules = await productionSchedulingService.forwardScheduleProductionOrder(
    productionOrder,
    new Date(startDate),
    userId
  );

  sendResponse(res, 200, true, 'Production Order forward scheduled successfully', schedules);
});

/**
 * Backward schedule a Production Order
 * POST /api/v1/production/schedule/backward/:productionOrderId
 */
exports.backwardSchedule = asyncHandler(async (req, res) => {
  const { productionOrderId } = req.params;
  const { finishDate } = req.body;
  const userId = req.user?.userId || null;

  if (!finishDate) {
    return sendError(res, 'Finish date is required', 400);
  }

  const productionOrder = await db.ProductionOrder.findByPk(productionOrderId, {
    include: [
      { model: db.Routing, as: 'routing' }
    ]
  });

  if (!productionOrder) {
    return sendError(res, 'Production Order not found', 404);
  }

  const schedules = await productionSchedulingService.backwardScheduleProductionOrder(
    productionOrder,
    new Date(finishDate),
    userId
  );

  sendResponse(res, 200, true, 'Production Order backward scheduled successfully', schedules);
});

/**
 * Get work center loadings
 * GET /api/v1/production/schedule/work-center-loading
 */
exports.getWorkCenterLoading = asyncHandler(async (req, res) => {
  const { companyId, plantId, startDate, endDate, workCenterId } = req.query;
  const userCompanyId = req.user?.companyId;

  if (!startDate || !endDate) {
    return sendError(res, 'Start date and end date are required', 400);
  }

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

  if (workCenterId) {
    // Get loading for specific work center
    const loading = await productionSchedulingService.getWorkCenterLoading(
      parseInt(workCenterId),
      new Date(startDate),
      new Date(endDate)
    );
    sendResponse(res, 200, true, 'Work center loading retrieved successfully', loading);
  } else {
    // Get loadings for all work centers
    const loadings = await productionSchedulingService.getWorkCenterLoadings(
      effectiveCompanyId,
      plantId || null,
      new Date(startDate),
      new Date(endDate)
    );
    sendResponse(res, 200, true, 'Work center loadings retrieved successfully', loadings);
  }
});

/**
 * Optimize production schedule
 * POST /api/v1/production/schedule/optimize
 */
exports.optimizeSchedule = asyncHandler(async (req, res) => {
  const { productionOrderIds, startDate, endDate, plantId } = req.body;
  const userId = req.user?.userId || null;
  const companyId = req.user?.companyId;

  if (!startDate || !endDate) {
    return sendError(res, 'Start date and end date are required', 400);
  }

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

  // If productionOrderIds is not provided or empty, optimize all active Production Orders
  const poIds = (productionOrderIds && Array.isArray(productionOrderIds) && productionOrderIds.length > 0) 
    ? productionOrderIds 
    : [];

  const result = await productionSchedulingService.optimizeSchedule(
    poIds,
    new Date(startDate),
    new Date(endDate),
    userId,
    companyId,
    plantId || null
  );

  sendResponse(res, 200, true, result.message || 'Schedule optimized successfully', result);
});

/**
 * Get schedule for a specific Production Order
 * GET /api/v1/production/schedule/production-order/:productionOrderId
 */
exports.getScheduleByProductionOrder = asyncHandler(async (req, res) => {
  const { productionOrderId } = req.params;

  const schedules = await db.ProductionSchedule.findAll({
    where: {
      production_order_id: productionOrderId
    },
    include: [
      { model: db.ProductionOrder, as: 'productionOrder' },
      { model: db.RoutingOperation, as: 'routingOperation' },
      { model: db.WorkCenter, as: 'workCenter' },
      { model: db.Plant, as: 'plant' }
    ],
    order: [['operation_number', 'ASC']]
  });

  sendResponse(res, 200, true, 'Production Order schedule retrieved successfully', schedules);
});

/**
 * Update schedule status
 * PUT /api/v1/production/schedule/:id/status
 */
exports.updateScheduleStatus = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const { schedule_status, remarks } = req.body;
  const userId = req.user?.userId || null;

  const schedule = await db.ProductionSchedule.findByPk(id);
  if (!schedule) {
    return sendError(res, 'Schedule not found', 404);
  }

  const updateData = {
    updated_by: userId
  };

  if (schedule_status) {
    const validStatuses = ['SCHEDULED', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED', 'ON_HOLD'];
    if (!validStatuses.includes(schedule_status)) {
      return sendError(res, `Invalid schedule status. Must be one of: ${validStatuses.join(', ')}`, 400);
    }
    updateData.schedule_status = schedule_status;
  }

  if (remarks !== undefined) {
    updateData.remarks = remarks;
  }

  await schedule.update(updateData);

  const updatedSchedule = await db.ProductionSchedule.findByPk(id, {
    include: [
      { model: db.ProductionOrder, as: 'productionOrder' },
      { model: db.RoutingOperation, as: 'routingOperation' },
      { model: db.WorkCenter, as: 'workCenter' }
    ]
  });

  sendResponse(res, 200, true, 'Schedule status updated successfully', updatedSchedule);
});

