const Bid = require('../models/bid.model');
const Wallet = require('../models/wallet.model');
const Account = require('../models/account.model');
const Product = require('../models/product.model');
const Transaction = require('../models/transactions.model');
const Order = require('../models/order.model');
const { conditionScoring } = require('../workers/bidScoring');
const { getGSMArenaPrice, getComputerPrice } = require('../utils/scrapper');
const { uploadImage } = require('../utils/cloudinary');
const axios = require('axios');
const NotificationService = require('../utils/notificationService');
const ProductService = require('../services/product');
const mongoose = require('mongoose');

/**
 * Helper to calculate condition score
 */
function calculateConditionScore(conditionDetails) {
  let score = 0;

  // Power button
  if (conditionDetails.autoOnOff) {
    score += conditionScoring.autoOnOff[conditionDetails.autoOnOff] || 0;
  }

  // Body condition
  if (conditionDetails.bodyCondition) {
    score +=
      conditionScoring.bodyCondition[conditionDetails.bodyCondition] || 0;
  }

  // Screen condition
  if (conditionDetails.screenCondition) {
    score +=
      conditionScoring.screenCondition[conditionDetails.screenCondition] || 0;
  }

  // Repair visits
  if (conditionDetails.repairVisits) {
    score += conditionScoring.repairVisits[conditionDetails.repairVisits] || 0;
  }

  // Biometrics
  if (conditionDetails.biometricFunction) {
    score +=
      conditionScoring.biometricFunction[conditionDetails.biometricFunction] ||
      0;
  }

  // Find my phone
  if (conditionDetails.findMyPhone) {
    score += conditionScoring.findMyPhone[conditionDetails.findMyPhone] || 0;
  }

  return score;
}

/**
 * Helper to calculate computer/laptop value based on specs and condition
 */
function calculateComputerValue(deviceDetails, conditionDetails) {
  let baseValue = 0;

  // Base value by brand
  const brandValues = {
    Apple: 150000,
    Dell: 80000,
    HP: 70000,
    Lenovo: 85000,
    Acer: 60000,
    Asus: 75000,
    Microsoft: 120000,
    Other: 50000,
  };

  baseValue = brandValues[deviceDetails.brand] || 50000;

  // Adjust by RAM
  const ramMultipliers = {
    '4GB': 0.7,
    '8GB': 1.0,
    '16GB': 1.3,
    '32GB': 1.6,
    '64GB': 2.0,
    Other: 1.0,
  };

  baseValue *= ramMultipliers[deviceDetails.ram] || 1.0;

  // Adjust by storage type
  const storageMultipliers = {
    HDD: 0.8,
    SSD: 1.2,
    Hybrid: 1.0,
    Other: 0.9,
  };

  baseValue *= storageMultipliers[deviceDetails.storageType] || 1.0;

  // Adjust by storage size
  if (deviceDetails.storageSize) {
    const storageSize = deviceDetails.storageSize.toLowerCase();
    if (storageSize.includes('128gb') || storageSize.includes('128')) {
      baseValue *= 0.9;
    } else if (storageSize.includes('256gb') || storageSize.includes('256')) {
      baseValue *= 1.0;
    } else if (storageSize.includes('512gb') || storageSize.includes('512')) {
      baseValue *= 1.2;
    } else if (storageSize.includes('1tb') || storageSize.includes('1000')) {
      baseValue *= 1.4;
    }
  }

  // Adjust by purchase year (age depreciation)
  if (deviceDetails.purchaseYear) {
    const currentYear = new Date().getFullYear();
    const purchaseYear = Number.parseInt(deviceDetails.purchaseYear);
    const age = currentYear - purchaseYear;
    const ageMultiplier = Math.max(0.3, 1 - age * 0.15);
    baseValue *= ageMultiplier;
  }

  // Adjust by condition
  if (conditionDetails) {
    const conditionMultipliers = {
      perfect: 1.0,
      good: 0.85,
      fair: 0.7,
      poor: 0.5,
      yes: 1.0,
      no: 0.8,
    };

    if (conditionDetails.bodyCondition) {
      baseValue *= conditionMultipliers[conditionDetails.bodyCondition] || 0.8;
    }

    if (conditionDetails.screenCondition) {
      baseValue *=
        conditionMultipliers[conditionDetails.screenCondition] || 0.8;
    }

    if (conditionDetails.autoOnOff === 'no') {
      baseValue *= 0.7; // Significant reduction for power issues
    }

    // Repair history impact
    const repairMultipliers = {
      0: 1.0,
      1: 0.9,
      '2-3': 0.8,
      'more-than-3-times': 0.6,
    };

    if (conditionDetails.repairVisits) {
      baseValue *= repairMultipliers[conditionDetails.repairVisits] || 0.9;
    }
  }

  return Math.round(baseValue);
}

/**
 * Helper to calculate mobile phone value based on specs and condition
 */
function calculateMobileValue(deviceDetails, conditionDetails) {
  let baseValue = 0;

  // Base value by brand
  const brandValues = {
    iOS: 200000,
    Samsung: 120000,
    Google: 100000,
    OnePlus: 80000,
    Xiaomi: 60000,
    Huawei: 70000,
    Infinix: 35000,
    Tecno: 30000,
    Other: 25000,
  };

  baseValue = brandValues[deviceDetails.brand] || 25000;

  // Adjust by storage
  const storageMultipliers = {
    '32GB': 0.7,
    '64GB': 0.9,
    '128GB': 1.0,
    '256GB': 1.3,
    '512GB': 1.6,
    '1TB': 2.0,
  };

  baseValue *= storageMultipliers[deviceDetails.storage] || 1.0;

  // Adjust by RAM
  const ramMultipliers = {
    '2GB': 0.6,
    '3GB': 0.7,
    '4GB': 0.8,
    '6GB': 1.0,
    '8GB': 1.2,
    '12GB': 1.4,
    '16GB': 1.6,
  };

  baseValue *= ramMultipliers[deviceDetails.ram] || 1.0;

  // Adjust by phone age
  const ageMultipliers = {
    '6-12 Months': 0.9,
    '1-2 years': 0.7,
    '2-3 years': 0.5,
    'Above 3 years': 0.3,
  };

  baseValue *= ageMultipliers[deviceDetails.phoneAge] || 0.8;

  // Adjust by condition
  if (conditionDetails) {
    const conditionMultipliers = {
      perfect: 1.0,
      minor_scratches: 0.85,
      dents: 0.7,
      cracked: 0.5,
      shattered: 0.3,
    };

    if (conditionDetails.bodyCondition) {
      baseValue *= conditionMultipliers[conditionDetails.bodyCondition] || 0.8;
    }

    if (conditionDetails.screenCondition) {
      baseValue *=
        conditionMultipliers[conditionDetails.screenCondition] || 0.8;
    }

    // Repair history impact
    const repairMultipliers = {
      0: 1.0,
      1: 0.9,
      '2-3': 0.8,
      'more-than-3-times': 0.6,
    };

    if (conditionDetails.repairVisits) {
      baseValue *= repairMultipliers[conditionDetails.repairVisits] || 0.9;
    }

    // Biometric function impact
    if (conditionDetails.biometricFunction === 'no') {
      baseValue *= 0.9;
    }
  }

  return Math.round(baseValue);
}

class BidController {
  static async createBid(req, res) {
    const session = await mongoose.startSession();
    session.startTransaction();
    
    try {
      const {
        productId,
        offeredProduct,
        bidType = 'swap',
        amount,
        message,
      } = req.body;
      const userId = req.user.id;

      if (!productId) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({
          error: 'Product ID is required',
        });
      }

      if (!mongoose.Types.ObjectId.isValid(productId)) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({ error: 'Invalid product ID format' });
      }

      const targetProduct = await Product.findById(productId).session(session);
      if (!targetProduct) {
        await session.abortTransaction();
        session.endSession();
        return res.status(404).json({ error: 'Target product not found' });
      }

      if (bidType === 'swap' && !targetProduct.swappable) {
        await session.abortTransaction();
        session.endSession();
        return res
          .status(400)
          .json({ error: 'Target product is not swappable' });
      }

      if (targetProduct.userId.toString() === userId) {
        await session.abortTransaction();
        session.endSession();
        return res
          .status(400)
          .json({ error: 'You cannot bid on your own product' });
      }

      let swapProductId = null;
      let bidAmount = amount || 0;

      let imageUrl = null;
      try {
        const uploadResult = await uploadImage(JSON.parse(offeredProduct).deviceImage);
        imageUrl = uploadResult;
      } catch (uploadError) {
        await session.abortTransaction();
        session.endSession();
        console.error('Image upload error:', uploadError);
        return res
          .status(500)
          .json({ error: 'Failed to upload product image' });
      }

      let offeredProductDetails = JSON.parse(offeredProduct);
      if (bidType === 'swap' && offeredProduct) {
        const swapProductData = {
          userId,
          name: offeredProductDetails.name,
          brand: offeredProductDetails.brand || 'Unknown',
          description: `Swap offer for ${targetProduct.name}`,
          price: offeredProductDetails.price,
          stock: 1,
          isActive: true,
          swappable: true,
          imageUrl: imageUrl,
          otherImages: [],
          category: offeredProductDetails.categoryId || null,
          conditionTag: offeredProductDetails.conditionTag || 'GOOD',
          verificationStatus: 'VERIFY',
        };

        const swapWithProduct = await ProductService.createProduct(
          swapProductData,
          { session }
        );
        swapProductId = swapWithProduct._id;
        bidAmount = swapWithProduct.price;
      }

      const [bid] = await Bid.create(
        [{
          amount: bidAmount,
          status: 'pending',
          swapWith: swapProductId,
          product: productId,
          user: userId,
          metaData: {
            bidType,
            message: message || null,
            offeredProductDetails: bidType === 'swap' ? offeredProductDetails : null,
          },
        }],
        { session }
      );

      const notificationTitle =
        bidType === 'swap' ? 'New Swap Offer Received' : 'New Bid Received';

      const notificationMessage =
        bidType === 'swap'
          ? `You received a swap offer for your ${targetProduct.name}. Check it out!`
          : `You received a bid of ₦${bidAmount.toLocaleString()} for your ${
              targetProduct.name
            }`;

      await NotificationService.sendNotification(
        targetProduct.userId,
        notificationTitle,
        notificationMessage,
        bidType === 'swap' ? 'swap_offer_received' : 'bid_received',
        {
          bidId: bid._id,
          productId: targetProduct._id,
          productName: targetProduct.name,
          offerAmount: bidAmount,
          bidType,
          swapProductId: swapProductId,
        }
      );

      await session.commitTransaction();
      session.endSession();

      return res.status(201).json({
        message: 'Bid created successfully',
        data: bid,
      });
    } catch (error) {
      await session.abortTransaction();
      session.endSession();
      console.error('Error creating bid:', error);
      return res.status(500).json({
        error: 'Internal server error',
        details: error.message,
      });
    }
  }

  static async getBidCalculator(req, res) {
    try {
      const { deviceType, deviceDetails, conditionDetails } = req.body;

      if (!deviceType || !deviceDetails || !deviceDetails.model) {
        return res.status(400).json({
          error: 'Missing required parameters: deviceType and deviceDetails',
        });
      }

      let estimatedValue = 0;
      let gsmPrice = null;
      let conditionAdjustedPrice = null;

      if (conditionDetails.autoOnOff.toLowerCase() == 'off') {
        return res
          .status(400)
          .json({ message: `Your device cannot be swapped` });
      }
      let conditionScore = calculateConditionScore({
        autoOnOff: conditionDetails.autoOnOff.toLowerCase(),
        bodyCondition: conditionDetails.bodyCondition.toLowerCase(),
        screenCondition: conditionDetails.screenCondition.toLowerCase(),
        repairVisits: conditionDetails.repairVisits.toLowerCase(),
        biometricFunction: conditionDetails.biometricFunction.toLowerCase(),
        findMyPhone: conditionDetails.findMyPhone || 'yes',
      });
      if (conditionScore < 50) {
        return res
          .status(400)
          .json({ message: `Your device cannot be swapped` });
      }

      if (deviceType === 'mobile') {
        // For mobile phones, try to get GSM Arena price first
        if (deviceDetails.model) {
          try {
            gsmPrice = await getGSMArenaPrice(deviceDetails.model, {
              ram: deviceDetails.ram,
              storage: deviceDetails.storage,
            });
          } catch (error) {
            console.log(
              'GSM Arena price not found, using fallback calculation'
            );
          }
        }

        if (gsmPrice && conditionDetails) {
          conditionAdjustedPrice = Number(gsmPrice) * (conditionScore / 100);
          estimatedValue = Math.round(conditionAdjustedPrice);
        } else {
          let price = calculateMobileValue(deviceDetails, conditionDetails);
          conditionAdjustedPrice = Number(price) * (conditionScore / 100);
          estimatedValue = Math.round(conditionAdjustedPrice);
        }
      } else if (deviceType === 'computer') {
        const price = await getComputerPrice(deviceDetails.model);
        if (!price || price == null) {
          let price = calculateComputerValue(deviceDetails, conditionDetails);
          conditionAdjustedPrice = Number(price) * (conditionScore / 100);
          estimatedValue = Math.round(conditionAdjustedPrice);
        } else {
          let price = price.ngn_price;
          conditionAdjustedPrice = Number(price) * (conditionScore / 100);
          estimatedValue = Math.round(conditionAdjustedPrice);
        }
      } else {
        return res.status(400).json({
          error: 'Unsupported device type. Supported types: mobile, computer',
        });
      }

      return res.status(200).json({
        success: true,
        deviceType,
        estimatedValue,
        conditionScore,
        gsmPrice: gsmPrice,
        conditionAdjustedPrice,
        breakdown: {
          baseValue:
            deviceType === 'mobile'
              ? gsmPrice
                ? gsmPrice
                : estimatedValue
              : estimatedValue,
          conditionMultiplier: conditionScore ? conditionScore / 100 : null,
          finalValue: estimatedValue,
        },
      });
    } catch (error) {
      console.error('Error getting bid calculator:', error);
      return res.status(500).json({ error: 'Internal server error' });
    }
  }

  /**
   * Accept a bid and create order
   */
  static async acceptBid(req, res) {
    const session = await mongoose.startSession();
    session.startTransaction();
    
    try {
      const { bidId } = req.params;
      const userId = req.user.id;

      if (!mongoose.Types.ObjectId.isValid(bidId)) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({ error: 'Invalid bid ID format' });
      }

      const bid = await Bid.findById(bidId)
        .populate('product')
        .populate('swapWith')
        .session(session);

      if (!bid) {
        await session.abortTransaction();
        session.endSession();
        return res.status(404).json({ error: 'Bid not found' });
      }

      if (bid.product.userId.toString() !== userId) {
        await session.abortTransaction();
        session.endSession();
        return res
          .status(403)
          .json({ error: 'You are not authorized to accept this bid' });
      }

      // Reject all other pending bids for this product
      await Bid.updateMany(
        {
          product: bid.product._id,
          _id: { $ne: bid._id },
          status: 'pending',
        },
        { status: 'rejected' },
        { session }
      );

      bid.status = 'accepted';
      await bid.save({ session });

      const orderProducts = [bid.product._id];
      const swapDetails = {
        targetProduct: bid.product._id,
        swapProduct: bid.swapWith?._id,
        targetProductPrice: bid.product.price,
        swapProductPrice: bid.swapWith?.price || 0,
        amountPaid: bid.amount,
        bidType: bid.metaData?.bidType || 'cash',
      };

      const [order] = await Order.create(
        [{
          user: bid.user,
          totalAmount: bid.amount,
          amountPaid: 0,
          swapped: bid.metaData?.bidType === 'swap',
          swap: orderProducts,
          swapDetails,
          address: '',
          status: 'pending',
          paymentCompleted: false,
          paymentMode: 'full',
        }],
        { session }
      );

      await NotificationService.sendNotification(
        bid.user,
        'Bid Accepted!',
        `Great news! Your ${
          bid.metaData?.bidType === 'swap' ? 'swap offer' : 'bid'
        } for ${
          bid.product.name
        } has been accepted. Complete your payment to finalize the transaction.`,
        'bid_accepted',
        {
          bidId: bid._id,
          orderId: order._id,
          productName: bid.product.name,
          offerAmount: bid.amount,
        }
      );

      // Notify rejected bidders
      const rejectedBids = await Bid.find({
        product: bid.product._id,
        _id: { $ne: bid._id },
        status: 'rejected',
      }).session(session);

      for (const rejectedBid of rejectedBids) {
        await NotificationService.sendNotification(
          rejectedBid.user,
          'Bid Not Selected',
          `Your ${
            rejectedBid.metaData?.bidType === 'swap' ? 'swap offer' : 'bid'
          } for ${
            bid.product.name
          } was not selected. Don't worry, there are many other great products available!`,
          'bid_rejected',
          {
            bidId: rejectedBid._id,
            productName: bid.product.name,
            offerAmount: rejectedBid.amount,
          }
        );
      }

      await session.commitTransaction();
      session.endSession();
      
      return res.status(201).json({
        message: 'Bid accepted and order created',
        data: {
          order,
          bid,
        },
      });
    } catch (error) {
      await session.abortTransaction();
      session.endSession();
      console.error('Error accepting bid:', error);
      return res.status(500).json({ error: 'Internal server error' });
    }
  }

  /**
   * Complete payment for a bid order
   */
  static async completeBidOrderPayment(req, res) {
    const session = await mongoose.startSession();
    session.startTransaction();
    
    try {
      const { orderId } = req.params;
      const { paymentMethod, address } = req.body;

      if (!mongoose.Types.ObjectId.isValid(orderId)) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({ error: 'Invalid order ID format' });
      }

      // Get order with products
      const order = await Order.findById(orderId)
        .populate({
          path: 'swap.product',
          model: 'Product'
        })
        .session(session);

      if (!order) {
        await session.abortTransaction();
        session.endSession();
        return res.status(404).json({ error: 'Order not found' });
      }

      if (!order.swapped) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({ error: 'This is not a swap order' });
      }

      if (order.paymentCompleted) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({ error: 'Order already paid' });
      }

      // Update address if provided
      if (address) {
        order.address = address;
        await order.save({ session });
      }

      // Get user and wallet
      const user = await Account.findById(order.user).session(session);
      const wallet = await Wallet.findOne({ user: order.user }).session(session);

      // Handle payment based on method
      if (paymentMethod === 'wallet') {
        // Check wallet balance
        if (wallet.balance < order.totalAmount) {
          await session.abortTransaction();
          session.endSession();
          return res.status(400).json({ error: 'Insufficient wallet balance' });
        }

        // Process wallet payment
        const [transactionRecord] = await Transaction.create(
          [{
            amount: order.totalAmount,
            reference: `WALLET-${Date.now()}`,
            type: 'debit',
            method: 'wallet',
            purpose: 'purchase',
            sender: wallet.user,
            receiver: order.user, // This might need adjustment based on your business logic
            status: 'success',
            description: `Payment for swap order #${order._id}`,
          }],
          { session }
        );

        // Update wallet balance
        wallet.balance -= order.totalAmount;
        await wallet.save({ session });

        // Update order
        order.transactionId = transactionRecord._id;
        order.amountPaid = order.totalAmount;
        order.paymentCompleted = true;
        order.status = 'completed';
        await order.save({ session });

        // Handle product ownership transfer
        const targetProduct = await Product.findById(order.swapDetails.targetProduct).session(session);
        if (targetProduct) {
          // Transfer target product to buyer
          targetProduct.userId = order.user;
          targetProduct.isActive = false; // Mark as sold
          await targetProduct.save({ session });
        }

        // If this was a product swap, transfer the swap product to the seller
        if (order.swapDetails.swapProduct) {
          const swapProduct = await Product.findById(order.swapDetails.swapProduct).session(session);
          if (swapProduct) {
            swapProduct.userId = user._id; // The original seller becomes owner of the swap product
            swapProduct.isActive = false; // Mark as sold
            await swapProduct.save({ session });
          }
        }

        await NotificationService.sendNotification(
          order.user,
          'Swap Completed Successfully!',
          `Your swap payment of ₦${order.totalAmount.toLocaleString()} has been processed. Your items will be exchanged soon!`,
          'bid_completed',
          {
            orderId: order._id,
            amount: order.totalAmount,
            transactionId: transactionRecord._id,
          }
        );

        await session.commitTransaction();
        session.endSession();
        
        return res.status(200).json({
          message: 'Swap order paid successfully via wallet',
          order,
          transaction: transactionRecord,
        });
      } else if (paymentMethod === 'paystack') {
        // Initialize Paystack payment
        const paystackResponse = await axios.post(
          'https://api.paystack.co/transaction/initialize',
          {
            email: user.email,
            amount: order.totalAmount * 100, // Paystack uses kobo
            reference: `PAYSTACK-${Date.now()}`,
            callback_url: `${process.env.FRONTEND_URL}/swap/verify/${order._id}`,
            metadata: {
              orderId: order._id,
              userId: order.user,
              isSwap: true,
              swapDetails: order.swapDetails,
              custom_fields: [
                {
                  display_name: 'Order ID',
                  variable_name: 'order_id',
                  value: order._id.toString(),
                },
                {
                  display_name: 'Swap Order',
                  variable_name: 'is_swap',
                  value: 'true',
                },
              ],
            },
          }
        );

        await session.commitTransaction();
        session.endSession();
        
        return res.status(200).json({
          message: 'Paystack payment initialized for swap order',
          paymentUrl: paystackResponse.data.data.authorization_url,
          order,
        });
      } else {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({ error: 'Invalid payment method' });
      }
    } catch (error) {
      await session.abortTransaction();
      session.endSession();
      console.error('Error completing bid order payment:', error);
      return res.status(500).json({ error: 'Internal server error' });
    }
  }

  /**
   * Get all bids for a product (for seller)
   */
  static async getProductBids(req, res) {
    try {
      const { productId } = req.params;

      if (!mongoose.Types.ObjectId.isValid(productId)) {
        return res.status(400).json({ error: 'Invalid product ID format' });
      }

      const bids = await Bid.find({ product: productId })
        .populate('user', 'firstName lastName email')
        .sort({ amount: -1 });

      return res.status(200).json({ bids });
    } catch (error) {
      console.error('Error fetching product bids:', error);
      return res.status(500).json({ error: 'Internal server error' });
    }
  }

  /**
   * Get user's bids
   */
  static async getUserBids(req, res) {
    try {
      const userId = req.user.id;

      // Get bids where user is the product owner (seller bids)
      const [sellerBids, buyerBids] = await Promise.all([
        Bid.find()
          .populate({
            path: 'product',
            match: { userId: userId },
            populate: {
              path: 'userId',
              model: 'Account',
              select: 'firstName lastName',
            },
          })
          .populate('user', 'firstName lastName')
          .sort({ createdAt: -1 }),
        Bid.find({ user: userId })
          .populate({
            path: 'product',
            populate: {
              path: 'userId',
              model: 'Account',
              select: 'firstName lastName',
            },
          })
          .populate({
            path: 'swapWith',
            populate: {
              path: 'userId',
              model: 'Account',
              select: 'firstName lastName',
            },
          })
          .sort({ createdAt: -1 }),
      ]);

      // Filter out bids where product is null (due to population match)
      const filteredSellerBids = sellerBids.filter(bid => bid.product !== null);

      return res.status(200).json({
        sellerBids: filteredSellerBids,
        buyerBids,
      });
    } catch (error) {
      console.error('Error fetching user bids:', error);
      return res.status(500).json({ error: 'Internal server error' });
    }
  }

  static async getBidById(req, res) {
    try {
      const bidId = req.params.bidId;

      if (!mongoose.Types.ObjectId.isValid(bidId)) {
        return res.status(400).json({ 
          status: false, 
          message: 'Invalid bid ID format' 
        });
      }

      const bid = await Bid.findById(bidId)
        .populate({
          path: 'product',
          populate: {
            path: 'userId',
            model: 'Account',
            select: 'firstName lastName verified',
          },
        })
        .populate({
          path: 'swapWith',
          populate: {
            path: 'userId',
            model: 'Account',
            select: 'firstName lastName',
          },
        })
        .populate('user', 'firstName lastName');

      if (!bid) {
        return res
          .status(404)
          .json({ status: false, message: 'Bid not found' });
      }

      // Flatten the response
      const response = {
        id: bid._id,
        amount: bid.amount,
        status: bid.status,
        createdAt: bid.createdAt,
        updatedAt: bid.updatedAt,
        // Product details
        image: bid.product?.imageUrl,
        brand: bid.product?.brand,
        name: bid.product?.name,
        description: bid.product?.description,
        price: bid.product?.price,
        verified: bid.product?.userId?.verified || false,
        location: bid.product?.metaData?.location || '',
        // Swap product details if exists
        swapOffer: bid.swapWith
          ? {
              id: bid.swapWith._id,
              image: bid.swapWith.imageUrl,
              name: bid.swapWith.name,
              brand: bid.swapWith.brand,
            }
          : null,
        // Add all metadata fields
        ...(bid.metaData || {}),
      };

      return res.status(200).json({ status: true, bid: response });
    } catch (err) {
      console.log(`Error getting bid: ${err}`);
      return res
        .status(500)
        .json({ status: false, message: 'Internal Server Error' });
    }
  }

  /**
   * Create a swap offer atomically (product + bid in single transaction)
   */
  static async createSwapOffer(req, res) {
    const session = await mongoose.startSession();
    session.startTransaction();
    
    try {
      const {
        targetProductId,
        name,
        categoryId,
        description,
        brand,
        price,
        ram,
        rom,
        displayType,
        displaySize,
        stock = '1',
        message,
      } = req.body;
      const userId = req.user.id;

      // Validate required fields
      if (
        !targetProductId ||
        !name ||
        !categoryId ||
        !description ||
        !brand ||
        !price
      ) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({
          error:
            'Missing required fields: targetProductId, name, categoryId, description, brand, price',
        });
      }

      if (!mongoose.Types.ObjectId.isValid(targetProductId)) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({ error: 'Invalid target product ID format' });
      }

      // Validate image upload
      if (!req.file) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({
          error: 'Product image is required',
        });
      }

      // Validate price
      const numericPrice = Number(price);
      if (isNaN(numericPrice) || numericPrice <= 0) {
        await session.abortTransaction();
        session.endSession();
        return res.status(400).json({
          error: 'Price must be a positive number',
        });
      }

      // Check if target product exists and is swappable
      const targetProduct = await Product.findById(targetProductId).session(session);
      if (!targetProduct) {
        await session.abortTransaction();
        session.endSession();
        return res.status(404).json({ error: 'Target product not found' });
      }

      if (!targetProduct.swappable) {
        await session.abortTransaction();
        session.endSession();
        return res
          .status(400)
          .json({ error: 'Target product is not swappable' });
      }

      // Prevent self-swapping
      if (targetProduct.userId.toString() === userId) {
        await session.abortTransaction();
        session.endSession();
        return res
          .status(400)
          .json({ error: 'You cannot make a swap offer on your own product' });
      }

      const fileBase64 = req.file.buffer.toString('base64');
      const dataUri = `data:${req.file.mimetype};base64,${fileBase64}`;
      
      // Upload image to Cloudinary
      let imageUrl = null;
      try {
        const uploadResult = await uploadImage(dataUri);
        imageUrl = uploadResult.secure_url || uploadResult;
      } catch (uploadError) {
        await session.abortTransaction();
        session.endSession();
        console.error('Image upload error:', uploadError);
        return res
          .status(500)
          .json({ error: 'Failed to upload product image' });
      }

      // Create the swap product with forSwapOnly = true
      const [swapProduct] = await Product.create(
        [{
          userId,
          name: name.trim(),
          category: categoryId,
          description: description.trim(),
          brand: brand.trim(),
          price: numericPrice,
          stock: Number(stock),
          isActive: true,
          swappable: false, // Swap products cannot be swapped again
          imageUrl,
          otherImages: [],
          conditionTag: 'GOOD', // Default condition
          verificationStatus: 'VERIFY',
          metaData: {
            createdForSwap: true,
            targetProductId: targetProductId,
            createdAt: new Date().toISOString(),
          },
        }],
        { session }
      );

      // Create the bid/swap offer
      const [bid] = await Bid.create(
        [{
          amount: numericPrice,
          status: 'pending',
          swapWith: swapProduct._id,
          product: targetProductId,
          user: userId,
          metaData: {
            bidType: 'swap',
            message: message || `Swap offer for ${targetProduct.name}`,
            swapProductId: swapProduct._id,
          },
        }],
        { session }
      );

      // Send notification to target product owner
      await NotificationService.sendNotification(
        targetProduct.userId,
        'New Swap Offer Received',
        `You received a swap offer for your ${targetProduct.name}. ${req.user.firstName} wants to swap their ${swapProduct.name} with your product.`,
        'swap_offer_received',
        {
          bidId: bid._id,
          productId: targetProduct._id,
          productName: targetProduct.name,
          swapProductId: swapProduct._id,
          swapProductName: swapProduct.name,
          offerAmount: numericPrice,
          bidType: 'swap',
        }
      );

      await session.commitTransaction();
      session.endSession();

      return res.status(201).json({
        message: 'Swap offer created successfully',
        data: {
          bid,
          swapProduct,
          targetProduct: {
            id: targetProduct._id,
            name: targetProduct.name,
          },
        },
      });
    } catch (error) {
      await session.abortTransaction();
      session.endSession();
      console.error('Error creating swap offer:', error);
      return res.status(500).json({ error: 'Internal server error' });
    }
  }
}

module.exports = BidController;