const Coupon = require('../models/Coupon');
const { NotFoundError, BadRequestError } = require('../utils/errors');

/**
 * @desc    Get all coupons with pagination and search
 * @route   GET /api/coupons
 * @access  Private/Admin
 */
const getAllCoupons = async (req, res, next) => {
  try {
    const { page = 1, limit = 10, search = '' } = req.query;
    const skip = (page - 1) * limit;
    
    const query = {};
    
    if (search) {
      query.$or = [
        { code: { $regex: search, $options: 'i' } },
        { description: { $regex: search, $options: 'i' } }
      ];
    }
    
    const [coupons, total] = await Promise.all([
      Coupon.find(query)
        .sort({ createdAt: -1 })
        .skip(skip)
        .limit(parseInt(limit)),
      Coupon.countDocuments(query)
    ]);
    
    const totalPages = Math.ceil(total / limit);
    
    res.json({
      success: true,
      count: coupons.length,
      total,
      totalPages,
      currentPage: parseInt(page),
      data: coupons
    });
  } catch (error) {
    next(error);
  }
};

/**
 * @desc    Get active coupons
 * @route   GET /api/coupons/active
 * @access  Public
 */
const getActiveCoupons = async (req, res, next) => {
  try {
    const now = new Date();
    const coupons = await Coupon.find({
      status: 'active',
      startDate: { $lte: now },
      $or: [
        { expiryDate: { $exists: false } },
        { expiryDate: null },
        { expiryDate: { $gte: now } }
      ]
    }).select('code description discountType discountValue minOrderAmount maxDiscountAmount');
    
    res.json({
      success: true,
      count: coupons.length,
      data: coupons
    });
  } catch (error) {
    next(error);
  }
};

/**
 * @desc    Get coupon by ID
 * @route   GET /api/coupons/:id
 * @access  Private/Admin
 */
const getCouponById = async (req, res, next) => {
  try {
    const coupon = await Coupon.findById(req.params.id);
    
    if (!coupon) {
      throw new NotFoundError('Coupon not found');
    }
    
    res.json({
      success: true,
      data: coupon
    });
  } catch (error) {
    next(error);
  }
};

/**
 * @desc    Create a new coupon
 * @route   POST /api/coupons
 * @access  Private/Admin
 */
const createCoupon = async (req, res, next) => {
  try {
    const {
      code,
      description,
      discount_type: discountType,
      discount_value: discountValue,
      min_order_amount: minOrderAmount = 0,
      max_discount: maxDiscountAmount,
      start_date: startDate,
      end_date: expiryDate,
      usage_limit: usageLimit,
      status = 'active'
    } = req.body;
    
    // Validate required fields
    if (!code || !discountType || discountValue === undefined) {
      throw new BadRequestError('Code, discount type, and discount value are required');
    }
    
    // Check if coupon code already exists
    const existingCoupon = await Coupon.findOne({ code });
    if (existingCoupon) {
      throw new BadRequestError('Coupon code already exists');
    }
    
    // Convert status to string if it's a boolean
    const statusValue = typeof status === 'boolean' ? (status ? 'active' : 'inactive') : status;
    
    // Create new coupon
    const coupon = new Coupon({
      code,
      description,
      discountType,
      discountValue: Number(discountValue),
      minOrderAmount: Number(minOrderAmount) || 0,
      maxDiscountAmount: discountType === 'percentage' ? Number(maxDiscountAmount) : undefined,
      startDate: startDate ? new Date(startDate) : new Date(),
      expiryDate: expiryDate ? new Date(expiryDate) : null,
      usageLimit: usageLimit ? Number(usageLimit) : null,
      status: statusValue
    });
    
    await coupon.save();
    
    res.status(201).json({
      success: true,
      data: coupon
    });
  } catch (error) {
    next(error);
  }
};

/**
 * @desc    Update a coupon
 * @route   PUT /api/coupons/:id
 * @access  Private/Admin
 */
const updateCoupon = async (req, res, next) => {
  try {
    const {
      code,
      description,
      discount_type,
      discount_value,
      min_order_amount,
      max_discount,
      start_date,
      end_date,
      usage_limit,
      status
    } = req.body;
    
    const coupon = await Coupon.findById(req.params.id);
    
    if (!coupon) {
      throw new NotFoundError('Coupon not found');
    }
    
    // Check if coupon code is being updated and if it already exists
    if (code && code !== coupon.code) {
      const existingCoupon = await Coupon.findOne({ code });
      if (existingCoupon) {
        throw new BadRequestError('Coupon code already exists');
      }
      coupon.code = code;
    }
    
    // Update fields if provided
    if (description !== undefined) coupon.description = description;
    if (discount_type) coupon.discountType = discount_type;
    if (discount_value !== undefined) coupon.discountValue = Number(discount_value);
    if (min_order_amount !== undefined) coupon.minOrderAmount = Number(min_order_amount);
    if (max_discount !== undefined) coupon.maxDiscountAmount = Number(max_discount) || undefined;
    if (start_date) coupon.startDate = new Date(start_date);
    if (end_date !== undefined) {
      coupon.expiryDate = end_date ? new Date(end_date) : null;
    }
    if (usage_limit !== undefined) {
      coupon.usageLimit = usage_limit ? Number(usage_limit) : null;
    }
    if (status !== undefined) {
      coupon.status = typeof status === 'boolean' ? (status ? 'active' : 'inactive') : status;
    }
    
    await coupon.save();
    
    // Return the updated coupon with consistent field names
    const response = {
      ...coupon.toObject(),
      discount_type: coupon.discountType,
      discount_value: coupon.discountValue,
      min_order_amount: coupon.minOrderAmount,
      max_discount: coupon.maxDiscountAmount,
      start_date: coupon.startDate?.toISOString().split('T')[0],
      end_date: coupon.expiryDate?.toISOString().split('T')[0],
      usage_limit: coupon.usageLimit,
      status: coupon.status === 'active'
    };
    
    res.json({
      success: true,
      data: response
    });
  } catch (error) {
    next(error);
  }
};

/**
 * @desc    Delete a coupon
 * @route   DELETE /api/coupons/:id
 * @access  Private/Admin
 */
const deleteCoupon = async (req, res, next) => {
  try {
    const coupon = await Coupon.findByIdAndDelete(req.params.id);
    
    if (!coupon) {
      throw new NotFoundError('Coupon not found');
    }
    
    res.json({
      success: true,
      data: {}
    });
  } catch (error) {
    next(error);
  }
};

/**
 * @desc    Toggle coupon status
 * @route   PATCH /api/coupons/:id/toggle-status
 * @access  Private/Admin
 */
const toggleCouponStatus = async (req, res, next) => {
  try {
    const coupon = await Coupon.findById(req.params.id);
    
    if (!coupon) {
      throw new NotFoundError('Coupon not found');
    }
    
    coupon.status = coupon.status === 'active' ? 'inactive' : 'active';
    await coupon.save();
    
    res.json({
      success: true,
      data: coupon
    });
  } catch (error) {
    next(error);
  }
};

/**
 * @desc    Get coupon statistics
 * @route   GET /api/coupons/analytics/statistics
 * @access  Private/Admin
 */
const getCouponStatistics = async (req, res, next) => {
  try {
    const [
      totalCoupons,
      activeCoupons,
      expiredCoupons,
      percentageCoupons,
      fixedCoupons
    ] = await Promise.all([
      Coupon.countDocuments(),
      Coupon.countDocuments({ status: 'active' }),
      Coupon.countDocuments({ 
        expiryDate: { $ne: null, $lt: new Date() } 
      }),
      Coupon.countDocuments({ discountType: 'percentage' }),
      Coupon.countDocuments({ discountType: 'fixed' })
    ]);
    
    res.json({
      success: true,
      data: {
        totalCoupons,
        activeCoupons,
        expiredCoupons,
        percentageCoupons,
        fixedCoupons,
        inactiveCoupons: totalCoupons - activeCoupons - expiredCoupons
      }
    });
  } catch (error) {
    next(error);
  }
};

/**
 * @desc    Search coupons
 * @route   GET /api/coupons/search
 * @access  Private/Admin
 */
const searchCoupons = async (req, res, next) => {
  try {
    const { query } = req.query;
    
    if (!query) {
      throw new BadRequestError('Search query is required');
    }
    
    const coupons = await Coupon.find({
      $or: [
        { code: { $regex: query, $options: 'i' } },
        { description: { $regex: query, $options: 'i' } }
      ]
    }).limit(10);
    
    res.json({
      success: true,
      count: coupons.length,
      data: coupons
    });
  } catch (error) {
    next(error);
  }
};

module.exports = {
  getAllCoupons,
  getCouponById,
  createCoupon,
  updateCoupon,
  deleteCoupon,
  toggleCouponStatus,
  getCouponStatistics,
  searchCoupons,
  getActiveCoupons
};