const express = require('express');
const router = express.Router();
const Order = require('../models/Order');
const User = require('../models/User');
const Notification = require('../models/Notification');
const Settings = require('../models/Settings'); // ✅ Changed from Setting to Settings
const { protect, captainOnly, clientOnly } = require('../middleware/authMiddleware');
const { validateOrder } = require('../middleware/validateMiddleware');
const nodemailer = require('nodemailer');
const { sendNotification } = require('../utils/notificationHelper');
const { sendWhatsAppIfSubscribed, OrderMessages } = require('../utils/whatsappNotificationHelper');
const rateLimit = require('express-rate-limit');
const { saveBase64Image } = require('../utils/imageUpload');
const { validateOrderLocations } = require('../utils/geofence');
const logger = require('../utils/logger');

// ⚡ Settings cache — refresh every 60 seconds to avoid repeated DB queries
let _settingsCache = null;
let _settingsCacheTime = 0;
async function getCachedSettings() {
    if (_settingsCache && Date.now() - _settingsCacheTime < 60_000) return _settingsCache;
    _settingsCache = await Settings.getSettings();
    _settingsCacheTime = Date.now();
    return _settingsCache;
}

// Rate Limiter للطلبات الجديدة
const createOrderLimiter = rateLimit({
    windowMs: 5 * 60 * 1000, // ✅ 5 minutes
    max: 5, // 5 requests per 5 minutes
    message: { message: 'لقد تجاوزت الحد المسموح به. يرجى الانتظار 5 دقائق.' },
    standardHeaders: true,
    legacyHeaders: false,
    validate: { xForwardedForHeader: false, trustProxy: false, ip: false }
});

// Rate Limiter للمفاوضات لمنع الإغراق
const negotiateLimiter = rateLimit({
    windowMs: 5 * 60 * 1000, // 5 minutes
    max: 30, // 30 requests per 5 minutes
    message: { message: 'لقد تجاوزت الحد المسموح به لمحاولات التفاوض. يرجى الانتظار 5 دقائق.' },
    standardHeaders: true,
    legacyHeaders: false,
    validate: { xForwardedForHeader: false, trustProxy: false, ip: false }
});

// Rate Limiter للتقييمات
const ratingLimiter = rateLimit({
    windowMs: 60 * 1000, // 1 minute
    max: 5,
    message: { message: 'يرجى الانتظار قليلاً قبل إرسال تقييم جديد.' },
    standardHeaders: true,
    legacyHeaders: false,
    validate: { xForwardedForHeader: false, trustProxy: false, ip: false }
});

const transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user: process.env.EMAIL_USER,
        pass: process.env.EMAIL_PASS
    }
});

// @route   POST /api/orders
// @desc    Create a new order (with duplicate check)
router.post('/', protect, createOrderLimiter, validateOrder, async (req, res) => {
    try {
        const { pickup, dropoff, details, price, distanceType, scheduledAt, orderType, shopId, shopName, shopPhone, items } = req.body;

        // Duplicate Check
        const oneMinuteAgo = new Date(Date.now() - 60 * 1000);
        const duplicateOrder = await Order.findOne({
            client: req.user.id,
            price: price,
            'pickup.address': pickup.address,
            status: { $in: ['pending', 'scheduled'] },
            createdAt: { $gt: oneMinuteAgo }
        });

        if (duplicateOrder) {
            return res.status(400).json({ message: 'You have already submitted this order recently' });
        }

        // 🇸🇩 Geofence: Validate locations are inside Sudan
        const geoCheck = validateOrderLocations(pickup, dropoff);
        if (!geoCheck.valid) {
            return res.status(400).json({ message: geoCheck.message });
        }

        // ✅ Get commission rate from unified Settings (stored as decimal e.g. 0.15 = 15%)
        const settings = await getCachedSettings();
        const commissionRate = settings.commissionRate ?? 0.15; // null-safe fallback only

        // ✅ Server-Side Security: Prevent clients from sending an abnormally low price
        const base = settings.baseFare || 1000;
        if (price < base) {
            return res.status(400).json({ message: `عذراً، السعر المطلوب (${price}) أقل من الحد الأدنى لتسعيرة النظام (${base})` });
        }

        const appFee = price * commissionRate;
        const netRevenue = price - appFee;

        // 🖼️ Store parcel image as-is (Base64 compressed on client ~500KB)
        // File system saving was unreliable on cPanel — MongoDB storage is safer
        const parcelImageUrl = req.body.parcelImage || null;

        // 🧾 Store receipt image as-is (Base64 compressed on client)
        const receiptImageUrl = req.body.receiptImage || null;

        // ⏰ Scheduled order support
        const isScheduled = scheduledAt && new Date(scheduledAt) > new Date();
        const orderStatus = isScheduled ? 'scheduled' : 'pending';

        const orderData = {
            client: req.user.id,
            pickup, dropoff, details, distanceType, price,
            appFee, netRevenue,
            parcelImage: parcelImageUrl,
            receiptImage: receiptImageUrl,
            status: orderStatus,
            scheduledAt: isScheduled ? new Date(scheduledAt) : null,
            orderType: orderType || 'delivery'
        };

        if (orderType === 'shop') {
            const Place = require('../models/Place');
            const place = await Place.findById(shopId);
            if (place && place.ownerId && place.ownerId.toString() === req.user.id.toString()) {
                return res.status(403).json({ message: 'لا يمكنك الطلب من متجرك الخاص' });
            }

            orderData.shopId = shopId;
            orderData.shopName = shopName;
            orderData.shopPhone = shopPhone;
            orderData.items = items;
            // حفظ تفاصيل الطلبية كنص (للعرض في كارت الكابتن)
            if (req.body.shopOrderDetails) {
                orderData.shopOrderDetails = req.body.shopOrderDetails;
            }
        }

        const order = await Order.create(orderData);

        // إشعار للكباتن فقط إذا الطلب فوري (ليس مجدولاً)
        if (!isScheduled) {
            const io = req.app.get('io');
            if (io) {
                if (orderType === 'shop') {
                    io.emit('shop_order_available', {
                        orderId: order._id,
                        shopName: order.shopName,
                        pickup: order.pickup.address,
                        price: order.price
                    });
                } else {
                    io.emit('new_order_available', {
                        orderId: order._id,
                        pickup: order.pickup.address,
                        price: order.price
                    });
                }

                // ✅ Notify admins via socket (for admin panel real-time feed)
                io.to('admin_room').emit('new_notification', {
                    title: '🆕 طلب جديد',
                    message: `طلب ${orderType === 'shop' ? 'محل' : 'توصيل'} جديد بسعر ${order.price} ج.س`,
                    type: 'admin_order_alert'
                });
                io.to('admin_room').emit('new_order_available', {
                    orderId: order._id,
                    pickup: orderType === 'shop' ? order.shopName : order.pickup.address,
                    price: order.price
                });
            }

            // 📣 Multicast Push for All Orders (Delivery & Shop)
            // Fire and forget to prevent HTTP timeouts
            setImmediate(async () => {
                try {
                    const { sendPushToMany, sendAdminPushToMany } = require('../utils/firebasePush');
                    
                    // 1. Send Push to Captains
                    const activeCaptains = await User.find({
                        role: 'captain',
                        fcmToken: { $exists: true, $ne: null },
                        isActive: true              // account not suspended by admin
                    }).select('fcmToken');

                    const tokens = activeCaptains.map(c => c.fcmToken);
                    if (tokens.length > 0) {
                        const title = orderType === 'shop' ? '🛒 طلب محل جديد! 🚨' : '📦 طلب توصيل جديد! 🚨';
                        const bodyMsg = orderType === 'shop'
                            ? `طلب من ${order.shopName || 'محل'} بسعر ${order.price} ج.س. عرض التفاصيل!`
                            : `طلب توصيل جديد متاح بسعر ${order.price} ج.س! عرض التفاصيل`;

                        await sendPushToMany(tokens, title, bodyMsg, {
                            type: orderType === 'shop' ? 'shop_order' : 'new_order',
                            orderId: order._id.toString()
                        });
                    }

                    // 2. Send Push to Admins (with distinct sound)
                    const admins = await User.find({
                        role: 'admin',
                        fcmToken: { $exists: true, $ne: null }
                    }).select('fcmToken name');

                    const adminTokens = admins.map(a => a.fcmToken).filter(t => t && t.length > 10);
                    if (adminTokens.length > 0) {
                         const adminTitle = orderType === 'shop' ? '🚨 طلب محل جديد (للإدارة)' : '🚨 طلب توصيل جديد (للإدارة)';
                         const adminBodyMsg = `تم استلام طلب جديد بقيمة ${order.price} ج.س ويتم الآن البحث عن كابتن.`;
                         
                         await sendAdminPushToMany(adminTokens, adminTitle, adminBodyMsg, {
                             type: 'admin_order_alert',
                             orderId: order._id.toString()
                         });
                    }
                } catch (pushErr) {
                    logger.error({ err: pushErr }, 'Multicast Push Failed in background');
                }
            });
        }

        const msg = isScheduled
            ? `تم جدولة طلبك بنجاح! سيُنشر للكباتن في ${new Date(scheduledAt).toLocaleString('ar-SA')}`
            : 'تم إنشاء الطلب بنجاح';

        res.status(201).json({ message: msg, order });
    } catch (error) {
        logger.error({ err: error }, 'Create Order Failed');
        res.status(500).json({ message: 'حدث خطأ في الخادم' });
    }
});

// @route   PUT /api/orders/:id/cancel
router.put('/:id/cancel', protect, async (req, res) => {
    try {
        let order = await Order.findById(req.params.id);
        
        // If not found in Order, check ShopOrder
        if (!order) {
            const ShopOrder = require('../models/ShopOrder');
            const shopOrder = await ShopOrder.findById(req.params.id);
            if (!shopOrder) return res.status(404).json({ message: 'Order not found' });
            
            if (shopOrder.client.toString() !== req.user.id) {
                return res.status(403).json({ message: 'You are not authorized to cancel this order' });
            }
            if (shopOrder.status !== 'shop_pending') {
                return res.status(400).json({ message: 'لا يمكن إلغاء الطلب لأن المتجر بدأ في تجهيزه' });
            }
            
            shopOrder.status = 'cancelled';
            shopOrder.cancelledBy = 'client';
            shopOrder.cancelReason = 'إلغاء من قبل العميل';
            await shopOrder.save();

            // ✅ FIX #2 + #14: استعادة المخزون عند إلغاء العميل لـ ShopOrder
            // (merchant/reject يفعل هذا بالفعل، لكن كان مفقوداً هنا)
            if (shopOrder.items && shopOrder.items.length > 0) {
                const Product = require('../models/Product');
                for (const item of shopOrder.items) {
                    if (item.productId) {
                        const prod = await Product.findById(item.productId).select('stock');
                        if (prod && prod.stock !== null && prod.stock !== undefined) {
                            await Product.findByIdAndUpdate(item.productId, {
                                $inc: { stock: item.quantity },
                                $set: { isAvailable: true }
                            });
                        }
                    }
                }
            }

            // Notify merchant and client/captain
            const io = req.app.get('io');
            if (io) {
                io.to(shopOrder.client.toString()).emit('order_status_updated', { orderId: shopOrder._id, status: 'cancelled' });
                if (shopOrder.captain) {
                    io.to(shopOrder.captain.toString()).emit('order_status_updated', { orderId: shopOrder._id, status: 'cancelled' });
                }
            }
            if (shopOrder.place) {
                const Place = require('../models/Place');
                const place = await Place.findById(shopOrder.place);
                if (place && place.ownerId) {
                    const io = req.app.get('io');
                    if (io) {
                        io.to(place.ownerId.toString()).emit('merchant_order_update', { orderId: shopOrder._id, status: 'cancelled' });
                    }
                    await sendNotification(req.app, {
                        userId: place.ownerId,
                        title: '⚠️ تم إلغاء الطلب',
                        message: `العميل قام بإلغاء الطلب رقم ${shopOrder._id.toString().slice(-6)}`,
                        type: 'order_update',
                        relatedId: shopOrder._id
                    });
                }
            }

            return res.json({ message: 'Order cancelled successfully', order: shopOrder });
        }

        // --- NORMAL ORDER CANCELLATION ---
        if (order.client.toString() !== req.user.id) {
            return res.status(403).json({ message: 'You are not authorized to cancel this order' });
        }
        
        // 🚀 FIX: Use findOneAndUpdate to prevent race conditions during cancellation
        const cancelledOrder = await Order.findOneAndUpdate(
            { _id: req.params.id, status: { $in: ['pending', 'scheduled'] }, client: req.user.id },
            { $set: { status: 'cancelled' } },
            { new: true }
        );
        if (!cancelledOrder) {
            return res.status(400).json({ message: 'This order cannot be cancelled as it is already in progress or completed' });
        }
        order = cancelledOrder; // update the local reference

        // 🚀 FIX 3: Notify negotiating captains when client cancels
        const io = req.app.get('io');
        if (order.negotiations && order.negotiations.length > 0) {
            for (let i = 0; i < order.negotiations.length; i++) {
                if (order.negotiations[i].status === 'pending') {
                    order.negotiations[i].status = 'rejected';
                    const capId = order.negotiations[i].captainId;
                    if (capId) {
                        if (io) {
                            io.to(capId.toString()).emit('negotiation_resolved', {
                                orderId: order._id,
                                result: 'order_taken' // reusing 'order_taken' to tell them it's gone
                            });
                        }
                        await sendNotification(req.app, {
                            userId: capId,
                            title: '⚠️ تم إلغاء الطلب',
                            message: 'قام العميل بإلغاء الطلب الذي قدمت عليه عرضاً.',
                            type: 'order_update',
                            relatedId: order._id
                        });
                    }
                }
            }
        }

        await order.save();
        
        // Notify admin and client about cancellation
        if (io) {
            io.emit('admin_order_update', { orderId: order._id, status: 'cancelled' });
            io.to(order.client.toString()).emit('order_status_updated', { orderId: order._id, status: 'cancelled' });
        }

        // إشعار للكابتن إذا كان هناك كابتن قد قبل الطلب
        if (order.captain) {
            if (io) {
                io.to(order.captain.toString()).emit('order_status_updated', { orderId: order._id, status: 'cancelled' });
            }
            await sendNotification(req.app, {
                userId: order.captain,
                title: '⚠️ تم إلغاء الطلب',
                message: `العميل قام بإلغاء الطلب رقم ${order._id.toString().slice(-6)}`,
                type: 'order_update',
                relatedId: order._id
            });
        }

        res.json({ message: 'Order cancelled successfully', order });
    } catch (error) {
        logger.error({ err: error }, 'Cancel order error');
        res.status(500).json({ message: 'Server error' });
    }
});

// @route   PUT /api/orders/shop/:id/upload-receipt
// @desc    Client uploads payment receipt for a shop order
router.put('/shop/:id/upload-receipt', protect, async (req, res) => {
    try {
        const ShopOrder = require('../models/ShopOrder');
        const Place = require('../models/Place');
        const { sendNotification } = require('../utils/notificationHelper');
        const { receiptImage } = req.body;
        if (!receiptImage) return res.status(400).json({ message: 'الرجاء إرفاق صورة الإشعار' });

        const order = await ShopOrder.findOne({ _id: req.params.id, client: req.user.id });
        if (!order) return res.status(404).json({ message: 'الطلب غير موجود' });
        
        order.paymentReceiptImage = receiptImage;
        order.paymentStatus = 'receipt_sent';
        await order.save();

        // Notify merchant
        const place = await Place.findById(order.place);
        if (place && place.ownerId) {
            await sendNotification(req.app, {
                userId: place.ownerId,
                title: '🧾 إشعار دفع جديد',
                message: `قام العميل بإرفاق إشعار الدفع للطلب رقم ${order._id.toString().slice(-6)}. يرجى مراجعته وتأكيده للبدء في التجهيز.`,
                type: 'shop_order_update',
                relatedId: order._id
            });
            const io = req.app.get('io');
            if (io) io.to(place.ownerId.toString()).emit('shop_order_updated', { orderId: order._id, status: 'receipt_sent' });
        }

        res.json({ message: 'تم إرسال إشعار الدفع للتاجر بنجاح', order });
    } catch (err) {
        logger.error({ err }, 'Upload shop receipt error');
        res.status(500).json({ message: 'Server error' });
    }
});

// @route   GET /api/orders/my-orders (للعميل)
router.get('/my-orders', protect, async (req, res) => {
    const startTime = Date.now();
    try {
        const page = parseInt(req.query.page) || 1;
        const limit = parseInt(req.query.limit) || 10;
        
        // Fetch normal Orders (excluding the cloned shop deliveries so we don't duplicate)
        const orders = await Order.find({ client: req.user.id, orderType: { $ne: 'shop' } })
            .select('-parcelImage')
            .populate('captain', 'name phone vehicleType currentLocation')
            .lean();

        // Fetch ShopOrders — BUG #30 FIX: exclude paymentReceiptImage to avoid leaking large base64 data
        const ShopOrder = require('../models/ShopOrder');
        const shopOrders = await ShopOrder.find({ client: req.user.id, status: { $ne: 'chat_initiated' } })
            .select('-paymentReceiptImage')
            .populate('place', 'name address bankAccountName bankAccountNumber bankName')
            .populate('captain', 'name phone vehicleType currentLocation')
            .lean();

        // Fetch corresponding delivery Orders for these ShopOrders to get negotiations
        const shopOrderIds = shopOrders.map(so => so._id);
        const deliveryOrders = await Order.find({ shopOrderId: { $in: shopOrderIds }, orderType: 'shop' })
            .select('negotiations shopOrderId captain')
            .lean();

        // Map ShopOrders to match Order format
        const mappedShopOrders = shopOrders.map(so => {
            const relatedDelivery = deliveryOrders.find(doObj => doObj.shopOrderId && doObj.shopOrderId.toString() === so._id.toString());
            
            let mappedStatus = 'pending';
            if (so.status === 'chat_initiated') mappedStatus = 'chat_initiated';
            else if (so.status === 'shop_pending') mappedStatus = 'pending';
            else if (so.status === 'shop_preparing' || so.status === 'ready_for_pickup' || so.status === 'captain_assigned') mappedStatus = 'accepted';
            else if (so.status === 'picked_up') mappedStatus = 'picked_up';
            else if (so.status === 'delivered') mappedStatus = 'delivered';
            else if (so.status === 'cancelled') mappedStatus = 'cancelled';

            return {
                _id: so._id,
                deliveryOrderId: relatedDelivery ? relatedDelivery._id : null, // Needed for negotiation
                negotiations: relatedDelivery ? relatedDelivery.negotiations : [],
                orderType: 'shop',
                shopOrderId: so._id,   // for chat linking
                placeId: so.place ? so.place._id : null,
                pickup: { address: so.place ? `🏖️ ${so.place.name}` : 'متجر' },
                dropoff: so.dropoff || { address: 'غير محدد' },
                price: so.totalAmount || 0,
                status: mappedStatus,
                realShopStatus: so.status,
                createdAt: so.createdAt,
                captain: so.captain || (relatedDelivery ? relatedDelivery.captain : null),
                isRated: false,
                proofOfPickupImage: so.proofOfPickupImage,
                paymentStatus: so.paymentStatus,
                hasReceipt: !!so.paymentReceiptImage, // BUG #30 FIX: boolean flag instead of full base64 image
                bankInfo: so.place ? {
                    name: so.place.bankAccountName,
                    account: so.place.bankAccountNumber,
                    bank: so.place.bankName
                } : null,
                details: (so.items && so.items.length > 0)
                    ? so.items.map(i => `${i.quantity}x ${i.name}`).join('، ')
                    : '💬 محادثة مباشرة'
            };
        });

        // Merge, sort, and paginate
        let allOrders = [...orders, ...mappedShopOrders].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
        const total = allOrders.length;
        const skip = (page - 1) * limit;
        const paginatedOrders = allOrders.slice(skip, skip + limit);

        logger.debug({ durationMs: Date.now() - startTime }, 'fetchMyOrders completed');

        res.json({
            orders: paginatedOrders,
            currentPage: page,
            totalPages: Math.ceil(total / limit),
            totalOrders: total
        });
    } catch (error) {
        logger.error({ err: error }, 'Fetch my-orders error');
        res.status(500).json({ message: 'خطأ' });
    }
});

// @route   GET /api/orders/my-missions (للكابتن - المهام الجارية)
router.get('/my-missions', protect, captainOnly, async (req, res) => {
    try {
        const orders = await Order.find({
            captain: req.user.id,
            status: { $in: ['accepted', 'picked_up'] }
        })
            .populate('client', 'name phone')
            .sort({ updatedAt: -1 });

        res.json(orders);
    } catch (err) {
        logger.error({ err }, 'Fetch my-missions error');
        res.status(500).json({ message: 'Server Error' });
    }
});

// @route   GET /api/orders (for captains — available orders)
router.get('/', protect, captainOnly, async (req, res) => {
    // 🚨 منع الكابتن المحظور من رؤية الطلبات الجديدة
    if (req.user.is_blocked) {
        return res.status(403).json({ message: 'حسابك موقوف مؤقتاً لتجاوزك الحد الائتماني للمديونية' });
    }

    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 10;
    const skip = (page - 1) * limit;

    try {
        // ✅ Show ALL pending orders — no longer lock on negotiation
        const orders = await Order.find({ status: 'pending' })
            .populate('client', 'name') // Phone removed for privacy before acceptance
            .sort({ createdAt: -1 })
            .skip(skip)
            .limit(limit);

        const total = await Order.countDocuments({ status: 'pending' });

        // ✅ For each order, flag if this captain already submitted an offer
        const captainId = req.user._id.toString();
        const enriched = orders.map(order => {
            const o = order.toObject();
            const myOffer = (o.negotiations || []).find(
                n => n.captainId && n.captainId.toString() === captainId && n.status === 'pending'
            );
            o.myOffer = myOffer || null;
            return o;
        });

        res.json({
            orders: enriched,
            currentPage: page,
            totalPages: Math.ceil(total / limit),
            totalOrders: total
        });
    } catch (err) {
        res.status(500).json({ message: 'Server Error' });
    }
});


// ==========================================
// 💬 التفاوض — كابتن يقترح سعر جديد (متعدد الكباتن)
// @route   PUT /api/orders/:id/negotiate
// ==========================================
router.put('/:id/negotiate', protect, captainOnly, async (req, res) => {
    // 🚨 منع الكابتن المحظور من التفاوض
    if (req.user.is_blocked) {
        return res.status(403).json({ message: 'حسابك محجوب ولا يمكنك تقديم عروض' });
    }

    try {
        const { proposedPrice } = req.body;
        if (!proposedPrice || proposedPrice <= 0) {
            return res.status(400).json({ message: 'يرجى إدخال سعر صحيح' });
        }

        const order = await Order.findById(req.params.id).populate('client', 'name');
        if (!order) return res.status(404).json({ message: 'الطلب غير موجود' });

        if (order.status !== 'pending') {
            return res.status(400).json({ message: 'الطلب غير متاح للتفاوض' });
        }

        // BUG #22 FIX: Prevent captain from negotiating on their own order
        if (req.user.id === order.client._id.toString()) {
            return res.status(403).json({ message: 'لا يمكنك التفاوض على طلبك الخاص' });
        }

        // Check if this captain already has an active offer
        const captainId = req.user._id.toString();
        const existingOffer = order.negotiations.find(
            n => n.captainId && n.captainId.toString() === captainId && n.status === 'pending'
        );
        if (existingOffer) {
            return res.status(400).json({ message: 'لديك عرض نشط بالفعل على هذا الطلب. يمكنك سحبه أولاً.' });
        }

        const expiresAt = new Date(Date.now() + 5 * 60 * 1000);

        // ✅ Push new offer to the negotiations array
        order.negotiations.push({
            captainId: req.user._id,
            captainName: req.user.name,
            proposedPrice,
            originalPrice: order.price,
            expiresAt,
            status: 'pending'
        });
        await order.save();

        // 🔔 Notify client via socket
        const io = req.app.get('io');
        if (io) {
            io.to(order.client._id.toString()).emit('negotiation_started', {
                orderId: order._id,
                captainName: req.user.name,
                captainId: req.user._id,
                originalPrice: order.price,
                proposedPrice,
                expiresAt
            });
        }

        // 🔔 Notification
        await sendNotification(req.app, {
            userId: order.client._id,
            title: '💬 عرض سعر جديد',
            message: `الكابتن ${req.user.name} يقترح سعر ${proposedPrice} ج.س بدلاً من ${order.price} ج.س`,
            type: 'order_update',
            relatedId: order._id
        });

        res.json({ message: 'تم إرسال عرض التفاوض', order });
    } catch (error) {
        logger.error({ err: error }, 'Negotiate Error');
        res.status(500).json({ message: 'Server Error' });
    }
});


// ==========================================
// 💬 رد العميل على عرض محدد
// @route   PUT /api/orders/:id/negotiate-response
// body: { action: 'accept'|'reject', captainId: '...' }
// ==========================================
router.put('/:id/negotiate-response', protect, negotiateLimiter, async (req, res) => {
    try {
        const { action, captainId } = req.body; // 'accept' or 'reject' + which captain's offer
        const order = await Order.findById(req.params.id);
        if (!order) return res.status(404).json({ message: 'الطلب غير موجود' });

        // 🚀 FIX 1: Ensure order is still pending before accepting negotiation
        if (order.status !== 'pending') {
            return res.status(400).json({ message: 'الطلب لم يعد متاحاً للتفاوض أو تم إغلاقه' });
        }

        // Only the client who owns the order can respond
        if (order.client.toString() !== req.user.id) {
            return res.status(403).json({ message: 'غير مصرح' });
        }

        if (!captainId) {
            return res.status(400).json({ message: 'يرجى تحديد الكابتن' });
        }

        // BUG #29 FIX: Validate captainId is a valid MongoDB ObjectId before using it
        const mongoose = require('mongoose');
        if (!mongoose.Types.ObjectId.isValid(captainId)) {
            return res.status(400).json({ message: 'معرف الكابتن غير صالح' });
        }

        // Find the specific offer in the negotiations array
        const offerIndex = order.negotiations.findIndex(
            n => n.captainId && n.captainId.toString() === captainId && n.status === 'pending'
        );

        if (offerIndex === -1) {
            return res.status(400).json({ message: 'لم يتم العثور على عرض نشط لهذا الكابتن' });
        }

        const offer = order.negotiations[offerIndex];

        // ✅ Check expiry
        if (offer.expiresAt && new Date() > new Date(offer.expiresAt)) {
            order.negotiations[offerIndex].status = 'expired';
            await order.save();
            return res.status(400).json({ message: 'انتهت صلاحية هذا العرض — الطلب متاح مجدداً للكباتن' });
        }

        const io = req.app.get('io');

        if (action === 'accept') {
            // Accept: update price, assign captain, change status
            order.price = offer.proposedPrice;
            order.captain = captainId;
            order.status = 'accepted';
            order.negotiations[offerIndex].status = 'accepted';

            // Reject all other pending negotiations
            order.negotiations.forEach((n, i) => {
                if (i !== offerIndex && n.status === 'pending') {
                    order.negotiations[i].status = 'rejected';
                }
            });

            // Clear legacy lock
            order.negotiation = { isActive: false, status: 'none' };

            // Recalculate fees
            const settings = await getCachedSettings();
            const commissionRate = settings.commissionRate ?? 0.15;
            order.appFee = order.price * commissionRate;
            order.netRevenue = order.price - order.appFee;

            // 🛡️ CRITICAL FIX: Atomic update for negotiation accept to prevent race condition with captain direct acceptance
            const updatedOrder = await Order.findOneAndUpdate(
                { _id: req.params.id, status: 'pending' },
                {
                    $set: {
                        price: order.price,
                        captain: order.captain,
                        status: 'accepted',
                        negotiation: order.negotiation,
                        negotiations: order.negotiations,
                        appFee: order.appFee,
                        netRevenue: order.netRevenue
                    }
                },
                { new: true }
            );

            if (!updatedOrder) {
                return res.status(400).json({ message: 'الطلب لم يعد متاحاً أو تم قبوله بالفعل' });
            }

            // Sync ShopOrder manually
            if (updatedOrder.shopOrderId) {
                try {
                    const ShopOrder = require('../models/ShopOrder');
                    await ShopOrder.findByIdAndUpdate(updatedOrder.shopOrderId, {
                        status: 'captain_assigned',
                        captain: updatedOrder.captain
                    });
                } catch (err) { logger.error('Error syncing ShopOrder negotiate', err); }
            }

            // Notify winning captain
            if (io) {
                io.to(captainId.toString()).emit('negotiation_resolved', {
                    orderId: order._id,
                    result: 'accepted',
                    finalPrice: order.price
                });
                io.to(order.client.toString()).emit('order_status_updated', {
                    orderId: order._id,
                    status: 'accepted',
                    captainId
                });
            }

            // ✅ FIX #4: استخدام updatedOrder.negotiations بدلاً من order.negotiations القديم
            // order.negotiations كانت تشير للكائن قبل findOneAndUpdate
            // وكانت فهرسة offerIndex تستخدم الترتيب القديم بدلاً من تحديد الكابتن الفائز بدقة
            const rejectedCaptains = updatedOrder.negotiations.filter(
                (n) => String(n.captainId) !== String(captainId) && n.captainId
            );
            for (const n of rejectedCaptains) {
                if (io) {
                    io.to(n.captainId.toString()).emit('negotiation_resolved', {
                        orderId: updatedOrder._id,
                        result: 'order_taken'
                    });
                }
                await sendNotification(req.app, {
                    userId: n.captainId,
                    title: '❌ قُبل عرض كابتن آخر',
                    message: 'تم قبول عرض كابتن آخر من قبل العميل.',
                    type: 'order_update',
                    relatedId: updatedOrder._id
                });
            }

            await sendNotification(req.app, {
                userId: captainId,
                title: '✅ تم قبول عرضك!',
                message: `العميل وافق على السعر ${order.price} ج.س — انطلق الآن!`,
                type: 'order_accepted',
                relatedId: order._id
            });

            res.json({ message: 'تم قبول العرض — الطلب مؤكد', order: updatedOrder });

        } else if (action === 'reject') {
            // Reject: mark only this offer as rejected
            order.negotiations[offerIndex].status = 'rejected';
            await order.save();

            // Notify that specific captain
            if (io) {
                io.to(captainId.toString()).emit('negotiation_resolved', {
                    orderId: order._id,
                    result: 'rejected'
                });
            }

            await sendNotification(req.app, {
                userId: captainId,
                title: '❌ تم رفض عرضك',
                message: 'العميل رفض السعر المقترح. الطلب لا يزال متاحاً.',
                type: 'order_update',
                relatedId: order._id
            });

            res.json({ message: 'تم رفض العرض — الطلب لا يزال متاحاً', order });
        } else {
            res.status(400).json({ message: 'action must be accept or reject' });
        }
    } catch (error) {
        logger.error({ err: error }, 'Negotiate Response Error');
        res.status(500).json({ message: 'Server Error' });
    }
});


// ==========================================
// 🚫 انسحاب الكابتن من عرضه
// @route   PUT /api/orders/:id/negotiate-withdraw
// ==========================================
router.put('/:id/negotiate-withdraw', protect, captainOnly, async (req, res) => {
    try {
        const order = await Order.findById(req.params.id);
        if (!order) return res.status(404).json({ message: 'الطلب غير موجود' });

        const captainId = req.user._id.toString();
        const offerIndex = order.negotiations.findIndex(
            n => n.captainId && n.captainId.toString() === captainId && n.status === 'pending'
        );

        if (offerIndex === -1) {
            return res.status(400).json({ message: 'لا يوجد عرض نشط لسحبه' });
        }

        order.negotiations[offerIndex].status = 'withdrawn';
        await order.save();

        // Notify client that the offer was withdrawn
        const io = req.app.get('io');
        if (io) {
            io.to(order.client.toString()).emit('negotiation_withdrawn', {
                orderId: order._id,
                captainId: req.user._id
            });
        }

        res.json({ message: 'تم سحب عرضك بنجاح', order });
    } catch (error) {
        logger.error({ err: error }, 'Withdraw Error');
        res.status(500).json({ message: 'Server Error' });
    }
});


// ============================================================
// 🔥🔥🔥 دالة القبول المعدلة (تم تصحيح اسم الحقل إلى message) 🔥🔥🔥
// @route   PUT /api/orders/:id/accept
// ============================================================
router.put('/:id/accept', protect, captainOnly, async (req, res) => {
    // 🚨 منع الكابتن المحظور من قبول الطلبات
    if (req.user.is_blocked) {
        return res.status(403).json({ message: 'حسابك محجوب ولا يمكنك استلام طلبات جديدة' });
    }

    try {
        // 🛡️ CRITICAL FIX: Atomic update to prevent Race Condition
        const updatedOrder = await Order.findOneAndUpdate(
            { _id: req.params.id, status: 'pending' },
            { 
                $set: { 
                    status: 'accepted', 
                    captain: req.user.id,
                    negotiation: { isActive: false, status: 'none' }
                }
            },
            { new: false } // return old document so we can check negotiations
        );

        if (!updatedOrder) {
            return res.status(400).json({ message: 'الطلب غير متاح أو تم قبوله من كابتن آخر' });
        }

        const order = await Order.findById(req.params.id); // Fetch the fresh updated document

        // 🚀 Clear negotiation state AND notify rejected captains
        const io = req.app.get('io');
        const rejectedCaptains = [];
        let negotiationsUpdated = false;
        
        if (order.negotiations && order.negotiations.length > 0) {
            order.negotiations.forEach((n, i) => {
                if (n.status === 'pending') {
                    order.negotiations[i].status = 'rejected';
                    negotiationsUpdated = true;
                    if (n.captainId && n.captainId.toString() !== req.user.id.toString()) {
                        rejectedCaptains.push(n.captainId);
                    }
                }
            });
            if (negotiationsUpdated) {
                await order.save(); // this will also trigger the post('save') hook!
            }
        } else {
             // If we didn't save the order (no negotiations to update), we must manually trigger post('save') logic for ShopOrder sync
             if (order.shopOrderId) {
                 try {
                     const ShopOrder = require('../models/ShopOrder');
                     await ShopOrder.findByIdAndUpdate(order.shopOrderId, {
                         status: 'captain_assigned',
                         captain: order.captain
                     });
                 } catch (err) { logger.error('Error syncing ShopOrder', err); }
             }
        }
        
        // Notify rejected captains
        for (const rCapId of rejectedCaptains) {
            if (io) {
                io.to(rCapId.toString()).emit('negotiation_resolved', {
                    orderId: order._id,
                    result: 'order_taken'
                });
            }
            await sendNotification(req.app, {
                userId: rCapId,
                title: '❌ قُبل عرض كابتن آخر',
                message: 'قام كابتن آخر بقبول الطلب مباشرة.',
                type: 'order_update',
                relatedId: order._id
            });
        }

        await sendNotification(req.app, {
            userId: order.client,
            title: '🎉 تم قبول طلبك!',
            message: `الكابتن ${req.user.name || 'متاح'} وافق على الطلب وهو في الطريق إليك.`,
            type: 'order_accepted',
            relatedId: order._id
        });

        await sendWhatsAppIfSubscribed(
            order.client,
            OrderMessages.orderAccepted(req.user.name || 'الكابتن', order._id.toString())
        );
        if (io) {
            io.to(order.client.toString()).emit('order_status_updated', {
                orderId: order._id,
                status: 'accepted',
                captainId: req.user.id
            });
            // Notify admin
            io.emit('admin_order_update', { orderId: order._id, status: 'accepted', captainName: req.user.name });
        }

        res.json({ message: 'Order accepted', order });
    } catch (error) {
        logger.error({ err: error }, 'Order accept error');
        res.status(500).json({ message: 'Server error: ' + error.message });
    }
});

// @route   PUT /api/orders/:id/pickup
router.put('/:id/pickup', protect, captainOnly, async (req, res) => {
    try {
        const { proofImage } = req.body;

        // 📸 إلزامي: يجب إرسال صورة إثبات الاستلام
        if (!proofImage) {
            return res.status(400).json({ message: 'يجب رفع صورة إثبات الاستلام قبل التأكيد' });
        }

        // 🛡️ CRITICAL FIX: Atomic update for pickup state
        const updatedOrder = await Order.findOneAndUpdate(
            { _id: req.params.id, captain: req.user.id, status: 'accepted' },
            { 
                $set: { 
                    status: 'picked_up',
                    proofOfPickupImage: proofImage
                }
            },
            { new: true }
        );

        if (!updatedOrder) {
            return res.status(400).json({ message: 'الطلب غير متاح أو تم تحديث حالته مسبقاً' });
        }
        
        const order = updatedOrder; // for subsequent logic

        // Sync ShopOrder manually since findOneAndUpdate bypasses post('save')
        if (order.shopOrderId) {
            try {
                const ShopOrder = require('../models/ShopOrder');
                await ShopOrder.findByIdAndUpdate(order.shopOrderId, { status: 'picked_up' });
            } catch (err) { logger.error('Error syncing ShopOrder pickup', err); }
        }

        await sendNotification(req.app, {
            userId: order.client,
            title: '📦 الكابتن استلم الطلب',
            message: `الكابتن ${req.user.name} قام باستلام طلبك الآن وهو في طريقه للتوصيل.`,
            type: 'order_update',
            relatedId: order._id
        });

        await sendWhatsAppIfSubscribed(
            order.client,
            OrderMessages.orderPickedUp(req.user.name || 'الكابتن', order._id.toString())
        );

        const io = req.app.get('io');
        if (io) {
            io.to(order.client.toString()).emit('order_status_updated', {
                orderId: order._id,
                status: 'picked_up',
                proofOfPickupImage: proofImage
            });
            io.emit('admin_order_update', { orderId: order._id, status: 'picked_up' });
        }

        res.json({ message: 'Order picked up', order });
    } catch (error) {
        res.status(500).json({ message: 'Server error' });
    }
});


// @route   PUT /api/orders/:id/deliver
router.put('/:id/deliver', protect, captainOnly, async (req, res) => {
    try {
        // 🛡️ CRITICAL FIX: Atomic update for delivery state to prevent Double Commission
        const updatedOrder = await Order.findOneAndUpdate(
            { _id: req.params.id, captain: req.user.id, status: 'picked_up' },
            { $set: { status: 'delivered', deliveredAt: new Date() } },
            { new: true }
        );

        if (!updatedOrder) {
            return res.status(400).json({ message: 'الطلب غير متاح للتوصيل أو تم توصيله مسبقاً.' });
        }
        
        const order = updatedOrder; // for subsequent logic

        // Sync ShopOrder manually since findOneAndUpdate bypasses post('save')
        if (order.shopOrderId) {
            try {
                const ShopOrder = require('../models/ShopOrder');
                await ShopOrder.findByIdAndUpdate(order.shopOrderId, { 
                    status: 'delivered',
                    deliveredAt: new Date()
                });
            } catch (err) { logger.error('Error syncing ShopOrder deliver', err); }
        }

        // 💳 Commission Deduction — Negative Wallet System
        let commissionRate = 0.15; // fallback 15% (matches schema default)
        let creditLimit    = -5000; // fallback
        try {
            const liveSettings = await getCachedSettings();
            // BUG #23 FIX: Unified commissionRate fallback — use != null check (same as line ~73)
            commissionRate = liveSettings?.commissionRate != null ? liveSettings.commissionRate : 0.15;
            if (liveSettings?.defaultCreditLimit)  creditLimit    = liveSettings.defaultCreditLimit;
        } catch (settingsErr) {
            logger.warn('Could not load settings, using defaults');
        }

        const orderPrice = order.price || 0;
        // 💳 NEGATIVE WALLET: commission is a DEBT — always subtract
        const commissionAmount = parseFloat((orderPrice * commissionRate).toFixed(2));

        // 🛡️ CRITICAL FIX: Atomic Wallet Deduction ($inc)
        const User = require('../models/User');
        const captain = await User.findByIdAndUpdate(
            order.captain,
            { $inc: { wallet_balance: -commissionAmount } },
            { new: true } // Returns the document AFTER the update
        );

        if (captain) {
            // ─── 📋 Detailed server log for verification ───
            logger.info({
                captain: captain.name,
                captainId: captain._id,
                orderId: order._id,
                orderPrice,
                commissionRate: (commissionRate * 100).toFixed(1) + '%',
                commissionAmount,
                newBalance: captain.wallet_balance,
                creditLimit
            }, 'Commission deducted atomically');

            // إيقاف الحساب تلقائياً إذا تجاوز الحد
            if (captain.wallet_balance <= creditLimit && !captain.is_blocked) {
                captain.is_blocked = true;
                await captain.save(); // save the blocked status
                logger.info({ captainId: captain._id, walletBalance: captain.wallet_balance, creditLimit }, 'Captain BLOCKED — exceeded credit limit');

                // 🔔 Push notification to captain
                try {
                    const { sendNotification } = require('../utils/notificationHelper');
                    await sendNotification(req.app, {
                        userId: captain._id,
                        title: '⛔ تم إيقاف حسابك',
                        message: 'تجاوزت الحد الائتماني. يرجى سداد المديونية لإعادة تفعيل الحساب.',
                        type: 'system',
                        relatedId: order._id
                    });
                } catch (notifErr) {
                    logger.error({ err: notifErr }, 'Block notification failed');
                }

                // 🔴 Real-Time Block: emit socket event to captain immediately
                const ioForBlock = req.app.get('io');
                if (ioForBlock) {
                    ioForBlock.to(captain._id.toString()).emit('wallet_limit_reached', {
                        wallet_balance: captain.wallet_balance,
                        credit_limit:   creditLimit,
                        message: 'تجاوزت الحد الائتماني — تم إيقاف حسابك.'
                    });
                    logger.info({ captainId: captain._id }, 'Emitted wallet_limit_reached to captain');
                }
            }
        }


        await sendNotification(req.app, {
            userId: order.client,
            title: '✅ تم التوصيل بنجاح',
            message: `تم توصيل طلبك بنجاح. شكراً لاستخدامك وصلي! لا تنسى تقييم الكابتن.`,
            type: 'order_completed',
            relatedId: order._id
        });

        await sendWhatsAppIfSubscribed(
            order.client,
            OrderMessages.orderDelivered(order._id.toString())
        );

        const io = req.app.get('io');
        if (io) {
            io.to(order.client.toString()).emit('order_status_updated', {
                orderId: order._id,
                status: 'delivered'
            });
            io.to(order.client.toString()).emit('delivery_attempted', {
                orderId: order._id
            });
            // 🔔 Notify admin about completed delivery
            io.emit('admin_order_update', { orderId: order._id, status: 'delivered', captainName: req.user.name, price: order.price });
        }

        res.json({ message: 'Order delivered', order });
    } catch (error) {
        res.status(500).json({ message: 'Server error' });
    }
});




// @route   POST /api/orders/:id/complain
router.post('/:id/complain', protect, async (req, res) => {
    try {
        const { text } = req.body;
        const order = await Order.findById(req.params.id);
        if (!order) return res.status(404).json({ message: 'Order not found' });
        if (order.client.toString() !== req.user.id) return res.status(403).json({ message: 'Not authorized' });

        order.complaint = { text, status: 'pending', createdAt: new Date() };
        await order.save();

        // ✅ Send notification to all admins about the complaint
        const admins = await User.find({ role: 'admin' });
        for (const admin of admins) {
            await sendNotification(req.app, {
                userId: admin._id,
                title: '⚠️ شكوى جديدة',
                message: `شكوى جديدة من العميل ${req.user.name || 'أحد العملاء'} على الطلب #${order._id.toString().slice(-6)}`,
                type: 'system',
                relatedId: order._id
            });
        }
        
        // Emit to admin dashboard
        const io = req.app.get('io');
        if (io) {
            io.to('admin_room').emit('new_notification', {
                title: '⚠️ شكوى جديدة',
                message: `شكوى جديدة من العميل ${req.user.name || 'أحد العملاء'} على الطلب #${order._id.toString().slice(-6)}`,
                type: 'system'
            });
        }

        res.json({ message: 'Complaint submitted', order });
    } catch (error) {
        res.status(500).json({ message: 'Server error' });
    }
});



// ==========================================
// ⭐ تقييم الكابتن (جديد)
// ==========================================
router.post('/:id/rate', protect, async (req, res) => {
    try {
        const { rating } = req.body; // 1-10
        const orderId = req.params.id;

        if (!rating || rating < 1 || rating > 10) {
            return res.status(400).json({ message: 'التقييم يجب أن يكون بين 1 و 10' });
        }

        let order = await Order.findOne({ _id: orderId, client: req.user._id });
        
        // If not found in Order, check ShopOrder
        if (!order) {
            const ShopOrder = require('../models/ShopOrder');
            order = await ShopOrder.findOne({ _id: orderId, client: req.user._id });
        }

        if (!order) return res.status(404).json({ message: 'الطلب غير موجود' });

        // BUG #21 FIX: Ensure the order is actually delivered before allowing rating
        if (order.status !== 'delivered') {
            return res.status(400).json({ message: 'يمكنك التقييم فقط بعد اكتمال التوصيل' });
        }

        // Prevent double rating
        if (order.isRated) {
            return res.status(400).json({ message: 'تم تقييم هذا الطلب مسبقاً' });
        }

        const captain = await User.findById(order.captain);
        if (!captain) return res.status(404).json({ message: 'الكابتن غير موجود' });

        // Update Captain Stats
        captain.ratingSum = (captain.ratingSum || 0) + rating;
        captain.ratingCount = (captain.ratingCount || 0) + 1;
        captain.averageRating = captain.ratingSum / captain.ratingCount;

        await captain.save();

        // ✅ Save rating in order (as object with score)
        order.rating = { score: rating, comment: '' };
        order.isRated = true;
        // Keep status as 'delivered' - no 'completed' status in schema
        await order.save();

        // ✅ Send notification to captain with rating
        await sendNotification(req.app, {
            userId: order.captain,
            title: rating >= 7 ? '⭐ تقييم ممتاز!' : rating >= 4 ? '⭐ تقييم جيد' : '⚠️ تقييم منخفض',
            message: `حصلت على تقييم ${rating}/10 من العميل ${req.user.name || 'أحد العملاء'}`,
            type: 'system',
            relatedId: order._id
        });

        res.json({ message: 'تم التقييم بنجاح', newAverage: captain.averageRating });

    } catch (error) {
        logger.error({ err: error }, 'Rate order error');
        res.status(500).json({ message: 'Server error' });
    }
});

// @route   GET /api/orders/price-config
// @desc    Get dynamic pricing settings for client calculation
// ✅ FIX #20: This named route MUST stay above GET /:id — otherwise Express treats
// 'price-config' as an :id param and passes it to findById(), causing a crash.
router.get('/price-config', protect, async (req, res) => {
    try {
        // ✅ FIX #7: Use getSettings() for consistency — enforces singleton, auto-creates if missing
        const settings = await getCachedSettings();
        res.json({
            baseFare: settings.baseFare ?? 1000,
            costPerKm: settings.costPerKm ?? 200,
            costPerMinute: settings.costPerMinute ?? 25
        });
    } catch (error) {
        logger.error({ err: error }, 'Price Config Error');
        res.status(500).json({ message: 'Server Error' });
    }
});

// @route   GET /api/orders/:id
// @desc    Get a single order by ID — accessible by its client, captain, admin, or any captain for pending orders
// ✅ FIX #20 (guard): Validate :id is a valid ObjectId before hitting DB
router.get('/:id', protect, async (req, res) => {
    try {
        const mongoose = require('mongoose');
        if (!mongoose.Types.ObjectId.isValid(req.params.id)) {
            return res.status(400).json({ message: 'معرف الطلب غير صحيح' });
        }

        const order = await Order.findById(req.params.id)
            .populate('client', 'name phone')
            .populate('captain', 'name phone vehicleType currentLocation')
            .lean();

        if (!order) return res.status(404).json({ message: 'الطلب غير موجود' });

        // Access control:
        // - The order's client can view it
        // - The assigned captain can view it
        // - Admin can view any
        // - ✅ ANY captain can view PENDING orders (no captain assigned yet) to see details before accepting
        const userId = req.user.id;
        const isClient = order.client && String(order.client._id) === userId;
        const isCaptain = order.captain && String(order.captain._id) === userId;
        const isAdmin = req.user.role === 'admin';
        // ✅ FIX #11: الكابتن المحجوب لا يمكنه رؤية تفاصيل أي طلب لا يخصه
        const isPendingAndUserIsCaptain = (
            order.status === 'pending' &&
            !order.captain &&
            req.user.role === 'captain' &&
            !req.user.is_blocked  // ✅ FIX: منع الكابتن المحجوب
        );

        if (!isClient && !isCaptain && !isAdmin && !isPendingAndUserIsCaptain) {
            return res.status(403).json({ message: 'غير مصرح' });
        }

        res.json(order);
    } catch (error) {
        logger.error({ err: error }, 'Get Order Error');
        res.status(500).json({ message: 'Server Error' });
    }
});

module.exports = router;