const { Order, OrderItem, Cart, CartItem, Product, ProductVariant, Coupon } = require('../models');
const { sequelize } = require('../models');
const CartService = require('./CartService');

class OrderService {
  async createOrder(userId, shippingData, paymentMethod = 'cod') {
    const cart = await CartService.getCart(userId, null);

    const items = await CartItem.findAll({
      where: { cartId: cart.id },
      include: [Product, ProductVariant],
    });

    if (!items.length) {
      throw new Error('Cart is empty.');
    }

    let coupon = null;
    if (cart.couponId) {
      coupon = await Coupon.findByPk(cart.couponId);
    }

    const { subtotal, discountAmount, taxAmount, shippingAmount, total } =
      CartService.calculateTotals(items, coupon);

    const orderNumber = 'ORD-' + Date.now() + '-' + Math.random().toString(36).substring(2, 6).toUpperCase();

    const result = await sequelize.transaction(async (t) => {
      const order = await Order.create({
        userId,
        orderNumber,
        subtotal,
        taxAmount,
        shippingAmount,
        discountAmount,
        total,
        paymentMethod,
        paymentStatus: paymentMethod === 'cod' ? 'pending' : 'pending',
        couponId: cart.couponId,
        shippingName: shippingData.shippingName,
        shippingPhone: shippingData.shippingPhone,
        shippingAddress: shippingData.shippingAddress,
        shippingCity: shippingData.shippingCity,
        shippingState: shippingData.shippingState,
        shippingPincode: shippingData.shippingPincode,
        shippingCountry: shippingData.shippingCountry || 'India',
        billingName: shippingData.billingName || shippingData.shippingName,
        billingAddress: shippingData.billingAddress || shippingData.shippingAddress,
        notes: shippingData.notes,
      }, { transaction: t });

      for (const item of items) {
        const product = item.Product;
        await OrderItem.create({
          orderId: order.id,
          productId: item.productId,
          productName: product.name,
          productSku: product.sku,
          variantInfo: item.ProductVariant ? `${item.ProductVariant.type}: ${item.ProductVariant.value}` : null,
          quantity: item.quantity,
          unitPrice: item.unitPrice,
          total: parseFloat(item.unitPrice) * item.quantity,
          imageUrl: null,
        }, { transaction: t });

        // Decrement stock
        await product.decrement('stockQuantity', { by: item.quantity, transaction: t });
      }

      // Increment coupon usage
      if (coupon) {
        await coupon.increment('usedCount', { by: 1, transaction: t });
      }

      // Clear cart
      await CartItem.destroy({ where: { cartId: cart.id }, transaction: t });
      cart.couponId = null;
      cart.discountAmount = 0;
      await cart.save({ transaction: t });

      return order;
    });

    return result;
  }

  async getUserOrders(userId, page = 1, limit = 10) {
    const offset = (page - 1) * limit;
    const { count, rows } = await Order.findAndCountAll({
      where: { userId },
      include: [{ model: OrderItem, as: 'items' }],
      order: [['createdAt', 'DESC']],
      offset,
      limit,
    });
    return { orders: rows, total: count, page, totalPages: Math.ceil(count / limit) };
  }

  async getOrderDetail(orderId, userId = null) {
    const where = { id: orderId };
    if (userId) where.userId = userId;
    return Order.findOne({
      where,
      include: [{ model: OrderItem, as: 'items' }],
    });
  }

  async getAllOrders(page = 1, limit = 20, filters = {}) {
    const offset = (page - 1) * limit;
    const where = {};
    if (filters.status) where.status = filters.status;
    if (filters.paymentStatus) where.paymentStatus = filters.paymentStatus;
    if (filters.search) {
      where[require('sequelize').Op.or] = [
        { orderNumber: { [require('sequelize').Op.like]: `%${filters.search}%` } },
      ];
    }

    const { count, rows } = await Order.findAndCountAll({
      where,
      include: [{ model: OrderItem, as: 'items' }],
      order: [['createdAt', 'DESC']],
      offset,
      limit,
    });
    return { orders: rows, total: count, page, totalPages: Math.ceil(count / limit) };
  }

  async updateOrderStatus(orderId, status) {
    const order = await Order.findByPk(orderId);
    if (!order) throw new Error('Order not found.');
    
    const updates = { status };
    if (status === 'shipped') updates.shippedAt = new Date();
    if (status === 'delivered') updates.deliveredAt = new Date();
    if (status === 'cancelled') updates.paymentStatus = 'refunded';

    await order.update(updates);
    return order;
  }
}

module.exports = new OrderService();
