const express = require('express');
const router = express.Router();
const emailService = require('../services/emailService'); // Import email service

module.exports = (pool, query, authMiddleware) => {
  // Apply authentication middleware to all routes
  router.use(authMiddleware);
  
  // Get all orders (admin only)
  router.get('/', async (req, res, next) => {
    try {
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      const result = await query(`
        SELECT o.*, 
               u.email, u.first_name, u.last_name,
               COUNT(oi.id) AS item_count
        FROM orders o
        JOIN users u ON o.user_id = u.id
        LEFT JOIN order_items oi ON o.id = oi.order_id
        GROUP BY o.id, u.id
        ORDER BY o.created_at DESC
      `);
      
      res.json(result.rows);
    } catch (error) {
      next(error);
    }
  });
  
  // Get single order with items
  router.get('/:id', async (req, res, next) => {
    try {
      const { id } = req.params;
      
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Get order details with shipping information
      const orderResult = await query(`
        SELECT o.*, 
               u.email, 
               u.first_name, 
               u.last_name,
               (SELECT EXISTS(
                 SELECT 1 FROM notification_logs
                 WHERE order_id = o.id AND notification_type = 'shipping_notification'
               )) as notification_sent
        FROM orders o
        JOIN users u ON o.user_id = u.id
        WHERE o.id = $1
      `, [id]);
      
      if (orderResult.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Order not found'
        });
      }
      
      // Get order items with product details
      const itemsResult = await query(`
        SELECT oi.*, 
               p.name as product_name, 
               p.description as product_description,
               pc.name as product_category,
               (
                 SELECT json_agg(
                   json_build_object(
                     'id', pi.id,
                     'path', pi.image_path,
                     'isPrimary', pi.is_primary,
                     'displayOrder', pi.display_order
                   ) ORDER BY pi.display_order
                 )
                 FROM product_images pi
                 WHERE pi.product_id = p.id
               ) AS product_images
        FROM order_items oi
        JOIN products p ON oi.product_id = p.id
        JOIN product_categories pc ON p.category_id = pc.id
        WHERE oi.order_id = $1
      `, [id]);
      
      // Combine order with items
      const order = {
        ...orderResult.rows[0],
        items: itemsResult.rows
      };
      
      res.json(order);
    } catch (error) {
      next(error);
    }
  });
  
  // Update order status with refund process
  router.patch('/:id', async (req, res, next) => {
    try {
      const { id } = req.params;
      const { status, refundReason } = req.body;
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Validate status
      const validStatuses = ['pending', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded'];
      if (!validStatuses.includes(status)) {
        return res.status(400).json({
          error: true,
          message: `Invalid status. Must be one of: ${validStatuses.join(', ')}`
        });
      }
      
      // Get order with customer information before updating
      const orderResult = await query(`
        SELECT o.*, o.payment_id, o.total_amount, u.email, u.first_name, u.last_name
        FROM orders o
        JOIN users u ON o.user_id = u.id
        WHERE o.id = $1
      `, [id]);
      
      if (orderResult.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Order not found'
        });
      }
      
      const order = orderResult.rows[0];
      
      // Begin transaction
      const client = await pool.connect();
      
      try {
        await client.query('BEGIN');
        
        // Special handling for refunded status
        if (status === 'refunded' && order.status !== 'refunded') {
          // Check if payment_id exists
          if (!order.payment_id) {
            await client.query('ROLLBACK');
            return res.status(400).json({
              error: true,
              message: 'Cannot refund order without payment information'
            });
          }
          
          try {
            // Process the refund with Stripe
            const stripe = require('stripe')(config.payment.stripeSecretKey);
            
            // If the payment ID is a Stripe Checkout session ID, get the associated payment intent
            let paymentIntentId = order.payment_id;
            
            // If it starts with 'cs_', it's a checkout session
            if (paymentIntentId.startsWith('cs_')) {
              const session = await stripe.checkout.sessions.retrieve(paymentIntentId);
              paymentIntentId = session.payment_intent;
            }
            
            // Create the refund
            const refund = await stripe.refunds.create({
              payment_intent: paymentIntentId,
              reason: 'requested_by_customer',
            });
            
            // Store refund information in the order
            const refundInfo = {
              refund_id: refund.id,
              amount: refund.amount / 100, // Convert from cents to dollars
              status: refund.status,
              reason: refundReason || 'Customer request',
              created: new Date(refund.created * 1000).toISOString(),
            };
            
            // Update order with refund information
            await client.query(`
              UPDATE orders
              SET status = $1, 
                  updated_at = NOW(),
                  payment_notes = CASE 
                    WHEN payment_notes IS NULL THEN $2::jsonb 
                    ELSE payment_notes::jsonb || $2::jsonb 
                  END
              WHERE id = $3
              RETURNING *
            `, [
              status, 
              JSON.stringify({ refund: refundInfo }), 
              id
            ]);
            
            // Send refund confirmation email
            await emailService.sendRefundConfirmation({
              to: order.email,
              first_name: order.first_name || 'Customer',
              order_id: order.id.substring(0, 8), // Use first 8 characters of UUID for cleaner display
              refund_amount: `$${refundInfo.amount.toFixed(2)}`,
              refund_date: new Date(refundInfo.created).toLocaleDateString(),
              refund_method: 'Original payment method',
              refund_reason: refundInfo.reason
            });
            
          } catch (stripeError) {
            console.error('Stripe refund error:', stripeError);
            await client.query('ROLLBACK');
            return res.status(400).json({
              error: true,
              message: `Failed to process refund: ${stripeError.message}`
            });
          }
        } else {
          // For non-refund status updates, just update the status
          await client.query(`
            UPDATE orders
            SET status = $1, updated_at = NOW()
            WHERE id = $2
          `, [status, id]);
        }
        
        await client.query('COMMIT');
        
        // Get updated order
        const updatedOrderResult = await query(
          'SELECT * FROM orders WHERE id = $1',
          [id]
        );
        
        res.json({
          message: 'Order status updated successfully',
          order: updatedOrderResult.rows[0]
        });
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    } catch (error) {
      next(error);
    }
  });
  
  router.post('/:id/refund', async (req, res, next) => {
    try {
      const { id } = req.params;
      const { 
        amount, 
        reason, 
        refundItems, // Optional: array of { item_id, quantity } for partial refunds
        sendEmail = true // Whether to send confirmation email
      } = req.body;
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Get order details with customer information
      const orderResult = await query(`
        SELECT o.*, o.payment_id, o.total_amount, u.email, u.first_name, u.last_name
        FROM orders o
        JOIN users u ON o.user_id = u.id
        WHERE o.id = $1
      `, [id]);
      
      if (orderResult.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Order not found'
        });
      }
      
      const order = orderResult.rows[0];
      
      // Check if payment_id exists
      if (!order.payment_id) {
        return res.status(400).json({
          error: true,
          message: 'Cannot refund order without payment information'
        });
      }
      
      // Begin transaction
      const client = await pool.connect();
      
      try {
        await client.query('BEGIN');
        
        // Determine if this is a full or partial refund
        const refundAmount = amount || order.total_amount;
        const isFullRefund = Math.abs(refundAmount - order.total_amount) < 0.01; // Account for possible floating point issues
        
        try {
          // Process the refund with Stripe
          const stripe = require('stripe')(config.payment.stripeSecretKey);
          
          // If the payment ID is a Stripe Checkout session ID, get the associated payment intent
          let paymentIntentId = order.payment_id;
          
          // If it starts with 'cs_', it's a checkout session
          if (paymentIntentId.startsWith('cs_')) {
            const session = await stripe.checkout.sessions.retrieve(paymentIntentId);
            paymentIntentId = session.payment_intent;
          }
          
          // Create the refund
          const refund = await stripe.refunds.create({
            payment_intent: paymentIntentId,
            amount: Math.round(refundAmount * 100), // Convert to cents for Stripe
            reason: 'requested_by_customer',
          });
          
          // Store refund information in the order
          const refundInfo = {
            refund_id: refund.id,
            amount: refund.amount / 100, // Convert from cents to dollars
            status: refund.status,
            reason: reason || 'Customer request',
            created: new Date(refund.created * 1000).toISOString(),
            is_full_refund: isFullRefund,
            refunded_items: refundItems || []
          };
          
          // Update order status and refund info
          if (isFullRefund) {
            // Full refund changes order status to refunded
            await client.query(`
              UPDATE orders
              SET status = 'refunded', 
                  updated_at = NOW(),
                  payment_notes = CASE 
                    WHEN payment_notes IS NULL THEN $1::jsonb 
                    ELSE payment_notes::jsonb || $1::jsonb 
                  END
              WHERE id = $2
            `, [
              JSON.stringify({ refund: refundInfo }), 
              id
            ]);
          } else {
            // Partial refund doesn't change order status
            await client.query(`
              UPDATE orders
              SET updated_at = NOW(),
                  payment_notes = CASE 
                    WHEN payment_notes IS NULL THEN $1::jsonb 
                    ELSE payment_notes::jsonb || $1::jsonb 
                  END
              WHERE id = $2
            `, [
              JSON.stringify({ partial_refund: refundInfo }), 
              id
            ]);
          }
          
          // If specific items were refunded, update their refund status in order_items
          if (refundItems && refundItems.length > 0) {
            for (const item of refundItems) {
              await client.query(`
                UPDATE order_items
                SET refunded = true, refunded_quantity = $1
                WHERE id = $2 AND order_id = $3
              `, [
                item.quantity, 
                item.item_id, 
                id
              ]);
            }
          }
          
          // Send refund confirmation email if requested
          if (sendEmail) {
            await emailService.sendRefundConfirmation({
              to: order.email,
              first_name: order.first_name || 'Customer',
              order_id: order.id.substring(0, 8), // Use first 8 characters of UUID for cleaner display
              refund_amount: `$${refundInfo.amount.toFixed(2)}`,
              refund_date: new Date(refundInfo.created).toLocaleDateString(),
              refund_method: 'Original payment method',
              refund_reason: refundInfo.reason
            });
          }
          
          await client.query('COMMIT');
          
          // Get the updated order
          const updatedOrderResult = await query(
            'SELECT * FROM orders WHERE id = $1',
            [id]
          );
          
          res.json({
            success: true,
            message: `${isFullRefund ? 'Full' : 'Partial'} refund processed successfully`,
            refund: refundInfo,
            order: updatedOrderResult.rows[0]
          });
          
        } catch (stripeError) {
          console.error('Stripe refund error:', stripeError);
          await client.query('ROLLBACK');
          return res.status(400).json({
            error: true,
            message: `Failed to process refund: ${stripeError.message}`
          });
        }
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    } catch (error) {
      next(error);
    }
  });

  // Update order status with shipping information and send notification
  router.patch('/:id/shipping', async (req, res, next) => {
    try {
      const { id } = req.params;
      const { status, shippingData, sendNotification } = req.body;
      
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Validate status
      const validStatuses = ['pending', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded'];
      if (!validStatuses.includes(status)) {
        return res.status(400).json({
          error: true,
          message: `Invalid status. Must be one of: ${validStatuses.join(', ')}`
        });
      }
      
      // Get order with customer information before updating
      const orderResult = await query(`
        SELECT o.*, u.email, u.first_name, u.last_name
        FROM orders o
        JOIN users u ON o.user_id = u.id
        WHERE o.id = $1
      `, [id]);
      
      if (orderResult.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Order not found'
        });
      }
      
      const order = orderResult.rows[0];
      
      // Begin transaction
      const client = await pool.connect();
      
      try {
        await client.query('BEGIN');
        
        // Store shipping information as JSON in the database
        const updatedOrder = await client.query(`
          UPDATE orders
          SET 
            status = $1, 
            updated_at = NOW(),
            shipping_info = $2,
            shipping_date = $3
          WHERE id = $4
          RETURNING *
        `, [
          status, 
          JSON.stringify(shippingData),
          new Date(), 
          id
        ]);
        
        // If status is 'shipped' and notification requested, send email
        if (status === 'shipped' && sendNotification) {
          // Get order items for the email
          const itemsResult = await client.query(`
            SELECT oi.*, p.name as product_name, p.price as original_price
            FROM order_items oi
            JOIN products p ON oi.product_id = p.id
            WHERE oi.order_id = $1
          `, [id]);
          
          const orderItems = itemsResult.rows;
          
          // Generate items HTML table
          const itemsHtml = orderItems.map(item => `
            <tr>
              <td style="padding: 10px; border-bottom: 1px solid #eee;">${item.product_name}</td>
              <td style="padding: 10px; border-bottom: 1px solid #eee;">${item.quantity}</td>
              <td style="padding: 10px; border-bottom: 1px solid #eee;">$${parseFloat(item.price_at_purchase).toFixed(2)}</td>
              <td style="padding: 10px; border-bottom: 1px solid #eee;">$${(parseFloat(item.price_at_purchase) * item.quantity).toFixed(2)}</td>
            </tr>
          `).join('');
          
          // Generate carrier tracking link
          let trackingLink = '#';
          const shipper = shippingData.shipper || '';
          const trackingNumber = shippingData.trackingNumber;

          if (trackingNumber) {
            // Match exactly with the values from the dropdown
            switch(shipper) {
              case 'USPS':
                trackingLink = `https://tools.usps.com/go/TrackConfirmAction?tLabels=${trackingNumber}`;
                break;
              case 'UPS':
                trackingLink = `https://www.ups.com/track?tracknum=${trackingNumber}`;
                break;
              case 'FedEx':
                trackingLink = `https://www.fedex.com/apps/fedextrack/?tracknumbers=${trackingNumber}`;
                break;
              case 'DHL':
                trackingLink = `https://www.dhl.com/global-en/home/tracking.html?tracking-id=${trackingNumber}`;
                break;
              case 'Canada Post':
                trackingLink = `https://www.canadapost-postescanada.ca/track-reperage/en#/search?searchFor=${trackingNumber}`;
                break;
              case 'Purolator':
                trackingLink = `https://www.purolator.com/en/shipping/track/tracking-number/${trackingNumber}`;
                break;
              default:
                // For "other" or any carrier not in our list
                // Just make the tracking number text without a link
                trackingLink = '#';
                break;
            }
          }
          
          // Format shipping date
          const shippedDate = new Date(shippingData.shippedDate || new Date()).toLocaleDateString();
          
          // Send email notification using template system
          await emailService.sendShippingNotification({
            to: order.email,
            first_name: order.first_name,
            order_id: order.id.substring(0, 8),
            tracking_number: shippingData.trackingNumber || 'N/A',
            carrier: shippingData.shipper || 'Standard Shipping',
            tracking_link: trackingLink,
            shipped_date: shippedDate,
            estimated_delivery: shippingData.estimatedDelivery || 'N/A',
            items_html: itemsHtml,
            customer_message: shippingData.customerMessage || ''
          });
          
          // Log the notification in the database
          await client.query(`
            INSERT INTO notification_logs (order_id, notification_type, sent_at)
            VALUES ($1, $2, NOW())
          `, [id, 'shipping_notification']);
        }
        
        await client.query('COMMIT');
        
        res.json({
          message: 'Order status updated successfully',
          order: updatedOrder.rows[0]
        });
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    } catch (error) {
      console.error('Error updating order status with shipping:', error);
      next(error);
    }
  });
  
  return router;
};