const Discount = require('../models/Discount');
const asyncHandler = require('../middleware/async');
const ErrorResponse = require('../utils/errorResponse');

// @desc    Get all discounts
// @route   GET /api/v1/discounts
// @access  Public
exports.getDiscounts = asyncHandler(async (req, res, next) => {
  const { page = 1, limit = 10, search, status, type } = req.query;
  
  // Build query
  const query = {};
  
  // Search by name or code
  if (search) {
    query.$or = [
      { name: { $regex: search, $options: 'i' } },
      { code: { $regex: search, $options: 'i' } }
    ];
  }
  
  // Filter by status
  if (status !== undefined) {
    query.status = status === 'true';
  }
  
  // Filter by type
  if (type) {
    query.type = type;
  }
  
  // Execute query with pagination
  const options = {
    page: parseInt(page, 10),
    limit: parseInt(limit, 10),
    sort: { createdAt: -1 }
  };
  
  try {
    console.log('Query:', query);
    console.log('Options:', options);
    
    const result = await Discount.paginate(query, options);
    
    if (!result || !Array.isArray(result.items)) {
      console.error('Invalid discounts data:', result);
      return next(new ErrorResponse('Failed to fetch discounts', 500));
    }
    
    console.log(`Found ${result.items.length} discounts`);
    
    res.status(200).json({
      success: true,
      count: result.items.length,
      data: result.items,
      pagination: {
        total: result.total,
        pages: result.totalPages,
        page: result.currentPage,
        limit: options.limit,
        hasNextPage: result.hasNextPage,
        hasPreviousPage: result.hasPreviousPage
      }
    });
  } catch (error) {
    console.error('Error fetching discounts:', error);
    return next(new ErrorResponse(`Error fetching discounts: ${error.message}`, 500));
  }
});

// @desc    Get single discount
// @route   GET /api/v1/discounts/:id
// @access  Public
exports.getDiscount = asyncHandler(async (req, res, next) => {
  const discount = await Discount.findById(req.params.id);
  
  if (!discount) {
    return next(
      new ErrorResponse(`Discount not found with id of ${req.params.id}`, 404)
    );
  }
  
  res.status(200).json({
    success: true,
    data: discount
  });
});

// @desc    Create new discount
// @route   POST /api/v1/discounts
// @access  Private/Admin
exports.createDiscount = asyncHandler(async (req, res, next) => {
  // Add user to req.body
  req.body.user = req.user.id;
  
  // If code is provided, ensure it's uppercase and has no spaces
  if (req.body.code) {
    req.body.code = req.body.code.toUpperCase().replace(/\s+/g, '');
  }
  
  const discount = await Discount.create(req.body);
  
  res.status(201).json({
    success: true,
    data: discount
  });
});

// @desc    Update discount
// @route   PUT /api/v1/discounts/:id
// @access  Private/Admin
exports.updateDiscount = asyncHandler(async (req, res, next) => {
  // First find the discount to ensure it exists
  let discount = await Discount.findById(req.params.id);
  
  if (!discount) {
    return next(
      new ErrorResponse(`Discount not found with id of ${req.params.id}`, 404)
    );
  }
  
  // If code is being updated, ensure it's uppercase and has no spaces
  if (req.body.code) {
    req.body.code = req.body.code.toUpperCase().replace(/\s+/g, '');
  }
  
  // Update the discount using the model instance
  Object.assign(discount, req.body);
  await discount.save();
  
  // Get the updated discount
  const updatedDiscount = await Discount.findById(req.params.id);
  
  res.status(200).json({
    success: true,
    data: updatedDiscount
  });
});

// @desc    Delete discount
// @route   DELETE /api/v1/discounts/:id
// @access  Private/Admin
// @desc    Delete discount
// @route   DELETE /api/v1/discounts/:id
// @access  Private/Admin
exports.deleteDiscount = asyncHandler(async (req, res, next) => {
  const discount = await Discount.deleteDiscount(req.params.id);
  
  if (!discount) {
    return next(
      new ErrorResponse(`Discount not found with id of ${req.params.id}`, 404)
    );
  }
  
  res.status(200).json({
    success: true,
    data: {}
  });
});

// @desc    Apply discount code
// @route   POST /api/v1/discounts/apply
// @access  Private
exports.applyDiscount = asyncHandler(async (req, res, next) => {
  const { code, cartTotal } = req.body;
  
  if (!code) {
    return next(new ErrorResponse('Please provide a discount code', 400));
  }
  
  if (cartTotal === undefined) {
    return next(new ErrorResponse('Please provide cart total', 400));
  }
  
  const result = await Discount.applyDiscount(code, parseFloat(cartTotal));
  
  if (!result.success) {
    return next(new ErrorResponse(result.message, 400));
  }
  
  res.status(200).json({
    success: true,
    data: result.discount,
    message: result.message
  });
});

// @desc    Get discount statistics
// @route   GET /api/v1/discounts/stats
// @access  Private/Admin
exports.getDiscountStats = asyncHandler(async (req, res, next) => {
  const stats = await Discount.getStatistics();
  
  res.status(200).json({
    success: true,
    data: stats
  });
});

// @desc    Get active discounts
// @route   GET /api/v1/discounts/active
// @access  Public
exports.getActiveDiscounts = asyncHandler(async (req, res, next) => {
  try {
    const currentDate = new Date();
    
    // Find active discounts that are either not time-bound or within their active period
    const discounts = await Discount.find({
      status: true,
      $and: [
        {
          $or: [
            { startDate: { $exists: false } },
            { startDate: { $lte: currentDate } }
          ]
        },
        {
          $or: [
            { endDate: { $exists: false } },
            { endDate: { $gte: currentDate } }
          ]
        }
      ]
    });
    
    // Map to only include necessary fields
    const formattedDiscounts = discounts.map(discount => ({
      _id: discount._id,
      name: discount.name,
      type: discount.type,
      value: discount.value,
      description: discount.description
    }));
    
    res.status(200).json({
      success: true,
      count: formattedDiscounts.length,
      data: formattedDiscounts
    });
  } catch (error) {
    console.error('Error in getActiveDiscounts:', error);
    next(error);
  }
});
