import redisClient from './redis-client';
import { sendTelegramMessage } from './telegram-service';

const ORDER_CHANNEL = 'orders:placed';

interface SimplifiedOrderItem {
  productName: string;
  quantity: number;
}

interface SimplifiedOrder {
  deliveryTime: string;
  orderPlaceTime: string;
  totalAmount: number;
  orderItems: SimplifiedOrderItem[];
}

interface FormattedOrderData {
  orders: SimplifiedOrder[];
}

/**
 * Format order details for Telegram message
 * @param orderData The order data to format
 * @returns Formatted message string
 */
const formatOrderMessage = (orderData: FormattedOrderData): string => {
  let message = '🛒 <b>New Order Placed</b>\n\n';
  
  orderData.orders.forEach((order, index) => {
    if (orderData.orders.length > 1) {
      message += `<b>Order ${index + 1}</b>\n`;
    }
    
    message += '📦 <b>Items:</b>\n';
    order.orderItems.forEach(item => {
      message += `  • ${item.productName} x${item.quantity}\n`;
    });
    
    message += `\n💰 <b>Total:</b> ₹${order.totalAmount}\n`;
    message += `🚚 <b>Delivery:</b> ${new Date(order.deliveryTime).toLocaleString()}\n`;
    message += `⏰ <b>Ordered:</b> ${new Date(order.orderPlaceTime).toLocaleString()}\n`;
    
    if (index < orderData.orders.length - 1) {
      message += '\n---\n\n';
    }
  });
  
  return message;
};

/**
 * Start the post order handler
 * Subscribes to the orders:placed channel and sends to Telegram
 */
export const startOrderHandler = async (): Promise<void> => {
  try {
    console.log('Starting post order handler...');
    
    await redisClient.subscribe(ORDER_CHANNEL, async (message: string) => {
      try {
        const orderDetails = JSON.parse(message);
        console.log('New order received, sending to Telegram...');
        
        const telegramMessage = formatOrderMessage(orderDetails);
        await sendTelegramMessage(telegramMessage);
      } catch (error) {
        console.error('Failed to process order message:', error);
        // Still try to send raw message to Telegram if parsing fails
        await sendTelegramMessage(`⚠️ Error parsing order: ${message}`);
      }
    });
    
    console.log('Post order handler started successfully');
  } catch (error) {
    console.error('Failed to start post order handler:', error);
    throw error;
  }
};

/**
 * Stop the post order handler
 */
export const stopOrderHandler = async (): Promise<void> => {
  try {
    await redisClient.unsubscribe(ORDER_CHANNEL);
    console.log('Post order handler stopped');
  } catch (error) {
    console.error('Error stopping post order handler:', error);
  }
};

/**
 * Publish order details to the queue
 * @param orderDetails Full order details to publish
 */
export const publishOrder = async (orderDetails: FormattedOrderData): Promise<boolean> => {
  try {
    const message = JSON.stringify(orderDetails);
    await redisClient.publish(ORDER_CHANNEL, message);
    return true;
  } catch (error) {
    console.error('Failed to publish order:', error);
    return false;
  }
};

/**
 * Mould raw order data into simplified format and publish
 * @param createdOrders Array of created orders from the database
 * @param ordersBySlot Map of slotId to items with product info
 * @returns Promise<boolean> indicating success or failure
 */
export const publishFormattedOrder = async (
  createdOrders: any[],
  ordersBySlot: Map<number | null, any[]>
): Promise<boolean> => {
  try {
    const simplifiedOrders: SimplifiedOrder[] = createdOrders.map(order => {
      // Get items for this order from ordersBySlot
      const slotItems = ordersBySlot.get(order.slotId) || [];
      
      // Map items to simplified format
      const orderItems: SimplifiedOrderItem[] = slotItems.map(item => ({
        productName: item.product?.name || 'Unknown Product',
        quantity: item.quantity,
      }));

      return {
        deliveryTime: order.slot?.deliveryTime?.toISOString() || order.deliveryDate?.toISOString() || new Date().toISOString(),
        orderPlaceTime: order.createdAt?.toISOString() || new Date().toISOString(),
        totalAmount: parseFloat(order.totalAmount?.toString() || '0'),
        orderItems,
      };
    });

    const formattedData: FormattedOrderData = {
      orders: simplifiedOrders,
    };

    return await publishOrder(formattedData);
  } catch (error) {
    console.error('Failed to format and publish order:', error);
    return false;
  }
};
