const express = require('express');
const router = express.Router();
const { body, validationResult } = require('express-validator');
const database = require('../config/database');
const { auth, optionalAuth, isAdmin } = require('../middleware/auth');
const { v4: uuidv4 } = require('uuid');
const { validateBookingLocations, getValidationMessage } = require('../utils/locationValidator');
const { sendBookingConfirmation } = require('../utils/emailService');

// Helper function to generate booking reference
function generateBookingReference() {
    const prefix = 'ASH';
    const timestamp = Date.now().toString().slice(-6);
    const random = Math.random().toString(36).substring(2, 6).toUpperCase();
    return `${prefix}${timestamp}${random}`;
}

// Helper function to calculate pricing
async function calculatePricing(vehicleId, distanceMiles, extras = [], isReturnJourney = false, isFirstBooking = false) {
    // Get vehicle pricing
    const vehicle = await database.get(
        'SELECT price_per_mile, minimum_fare FROM vehicles WHERE id = ?',
        [vehicleId]
    );

    if (!vehicle) {
        throw new Error('Vehicle not found');
    }

    // Calculate base fare
    let baseFare = Math.max(vehicle.minimum_fare, distanceMiles * vehicle.price_per_mile);

    // Calculate extras
    let extrasTotal = 0;
    for (const extraId of extras) {
        const extra = await database.get(
            'SELECT price FROM extras WHERE id = ? AND is_active = 1',
            [extraId]
        );
        if (extra) {
            extrasTotal += extra.price;
        }
    }

    // Calculate subtotal
    let subtotal = baseFare + extrasTotal;
    let discountAmount = 0;
    let discountType = [];

    // Apply return journey discount
    if (isReturnJourney) {
        const returnDiscount = await database.get(
            "SELECT config_value FROM pricing_config WHERE config_key = 'return_discount_percent'"
        );
        const discountPercent = parseFloat(returnDiscount?.config_value || 10);
        const discount = (subtotal * discountPercent) / 100;
        discountAmount += discount;
        discountType.push(`Return Journey (${discountPercent}%)`);
    }

    // Apply first booking discount
    if (isFirstBooking) {
        const firstRideDiscount = await database.get(
            "SELECT config_value FROM pricing_config WHERE config_key = 'first_ride_discount_percent'"
        );
        const discountPercent = parseFloat(firstRideDiscount?.config_value || 10);
        const discount = (subtotal * discountPercent) / 100;
        discountAmount += discount;
        discountType.push(`First Ride (${discountPercent}%)`);
    }

    const totalPrice = subtotal - discountAmount;

    return {
        baseFare: parseFloat(baseFare.toFixed(2)),
        extrasTotal: parseFloat(extrasTotal.toFixed(2)),
        discountAmount: parseFloat(discountAmount.toFixed(2)),
        discountType: discountType.join(', '),
        totalPrice: parseFloat(totalPrice.toFixed(2))
    };
}

// Create new booking
router.post('/', optionalAuth,
    [
        body('pickup_location').trim().notEmpty(),
        body('dropoff_location').trim().notEmpty(),
        body('pickup_date').isDate(),
        body('pickup_time').matches(/^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/),
        body('vehicle_id').isInt(),
        body('passengers').isInt({ min: 1 }),
        body('distance_miles').isFloat({ min: 0.1 }),
        body('guest_email').optional().isEmail(),
        body('guest_name').optional().trim(),
        body('guest_phone').optional().trim()
    ],
    async (req, res) => {
        try {
            const errors = validationResult(req);
            if (!errors.isEmpty()) {
                return res.status(400).json({ errors: errors.array() });
            }

            const {
                pickup_location,
                pickup_postcode,
                dropoff_location,
                dropoff_postcode,
                distance_miles,
                pickup_date,
                pickup_time,
                vehicle_id,
                passengers,
                extras,
                is_return_journey,
                return_journey,
                guest_email,
                guest_name,
                guest_phone,
                customer_notes
            } = req.body;

            // Validate location restrictions
            const locationValidation = validateBookingLocations(
                pickup_location + ' ' + (pickup_postcode || ''),
                dropoff_location + ' ' + (dropoff_postcode || '')
            );

            if (!locationValidation.valid) {
                return res.status(400).json({
                    error: 'Location not in service area',
                    message: getValidationMessage(locationValidation),
                    details: locationValidation.details
                });
            }

            // Determine if authenticated user or guest
            const userId = req.user?.id || null;
            let isFirstBooking = false;

            if (userId) {
                const user = await database.get(
                    'SELECT is_first_booking FROM users WHERE id = ?',
                    [userId]
                );
                isFirstBooking = user?.is_first_booking === 1;
            }

            // Calculate pricing
            const pricing = await calculatePricing(
                vehicle_id,
                distance_miles,
                extras || [],
                is_return_journey || false,
                isFirstBooking
            );

            // Generate booking reference
            const bookingReference = generateBookingReference();

            // Insert booking
            const result = await database.run(
                `INSERT INTO bookings (
                    booking_reference, user_id, guest_email, guest_name, guest_phone,
                    pickup_location, pickup_postcode, dropoff_location, dropoff_postcode,
                    distance_miles, pickup_date, pickup_time, vehicle_id, passengers,
                    base_fare, extras_total, discount_amount, discount_type, total_price,
                    is_return_journey, return_pickup_location, return_dropoff_location,
                    return_pickup_date, return_pickup_time, return_distance_miles,
                    customer_notes, status, payment_status
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', 'pending')`,
                [
                    bookingReference, userId, guest_email || null, guest_name || null, guest_phone || null,
                    pickup_location, pickup_postcode || null, dropoff_location, dropoff_postcode || null,
                    distance_miles, pickup_date, pickup_time, vehicle_id, passengers,
                    pricing.baseFare, pricing.extrasTotal, pricing.discountAmount, pricing.discountType,
                    pricing.totalPrice, is_return_journey ? 1 : 0,
                    return_journey?.pickup_location || null,
                    return_journey?.dropoff_location || null,
                    return_journey?.pickup_date || null,
                    return_journey?.pickup_time || null,
                    return_journey?.distance_miles || null,
                    customer_notes || null
                ]
            );

            const bookingId = result.id;

            // Insert booking extras
            if (extras && extras.length > 0) {
                for (const extraId of extras) {
                    const extra = await database.get('SELECT price FROM extras WHERE id = ?', [extraId]);
                    if (extra) {
                        await database.run(
                            'INSERT INTO booking_extras (booking_id, extra_id, quantity, price) VALUES (?, ?, 1, ?)',
                            [bookingId, extraId, extra.price]
                        );
                    }
                }
            }

            // Update user's first booking flag
            if (userId && isFirstBooking) {
                await database.run(
                    'UPDATE users SET is_first_booking = 0 WHERE id = ?',
                    [userId]
                );
            }

            // Get complete booking details
            const booking = await database.get(
                `SELECT b.*, v.name as vehicle_name, v.type as vehicle_type
                 FROM bookings b
                 JOIN vehicles v ON b.vehicle_id = v.id
                 WHERE b.id = ?`,
                [bookingId]
            );

            // Send confirmation emails (async, don't wait)
            sendBookingConfirmation(booking).catch(err => {
                console.error('Failed to send booking confirmation email:', err);
            });

            res.status(201).json({
                message: 'Booking created successfully',
                booking
            });
        } catch (error) {
            console.error('Create booking error:', error);
            res.status(500).json({ error: 'Failed to create booking' });
        }
    }
);

// Get user's bookings
router.get('/my-bookings', auth, async (req, res) => {
    try {
        const { status, limit = 10, offset = 0 } = req.query;

        let sql = `
            SELECT b.*, v.name as vehicle_name, v.type as vehicle_type
            FROM bookings b
            JOIN vehicles v ON b.vehicle_id = v.id
            WHERE b.user_id = ?
        `;
        const params = [req.user.id];

        if (status) {
            sql += ' AND b.status = ?';
            params.push(status);
        }

        sql += ' ORDER BY b.pickup_date DESC, b.pickup_time DESC LIMIT ? OFFSET ?';
        params.push(parseInt(limit), parseInt(offset));

        const bookings = await database.all(sql, params);

        // Get extras for each booking
        for (const booking of bookings) {
            const extras = await database.all(
                `SELECT e.id, e.name, e.description, be.price
                 FROM booking_extras be
                 JOIN extras e ON be.extra_id = e.id
                 WHERE be.booking_id = ?`,
                [booking.id]
            );
            booking.extras = extras;
        }

        res.json({ bookings });
    } catch (error) {
        console.error('Get bookings error:', error);
        res.status(500).json({ error: 'Failed to fetch bookings' });
    }
});

// Get single booking
router.get('/:id', auth, async (req, res) => {
    try {
        const booking = await database.get(
            `SELECT b.*, v.name as vehicle_name, v.type as vehicle_type,
                    u.first_name, u.last_name, u.email, u.phone
             FROM bookings b
             JOIN vehicles v ON b.vehicle_id = v.id
             LEFT JOIN users u ON b.user_id = u.id
             WHERE b.id = ? AND (b.user_id = ? OR ? = 'admin')`,
            [req.params.id, req.user.id, req.user.role]
        );

        if (!booking) {
            return res.status(404).json({ error: 'Booking not found' });
        }

        // Get extras
        const extras = await database.all(
            `SELECT e.id, e.name, e.description, be.price
             FROM booking_extras be
             JOIN extras e ON be.extra_id = e.id
             WHERE be.booking_id = ?`,
            [booking.id]
        );
        booking.extras = extras;

        res.json({ booking });
    } catch (error) {
        console.error('Get booking error:', error);
        res.status(500).json({ error: 'Failed to fetch booking' });
    }
});

// Admin: Get all bookings
router.get('/', auth, isAdmin, async (req, res) => {
    try {
        const { status, date_from, date_to, limit = 50, offset = 0 } = req.query;

        let sql = `
            SELECT b.*, v.name as vehicle_name, v.type as vehicle_type,
                   u.first_name, u.last_name, u.email
            FROM bookings b
            JOIN vehicles v ON b.vehicle_id = v.id
            LEFT JOIN users u ON b.user_id = u.id
            WHERE 1=1
        `;
        const params = [];

        if (status) {
            sql += ' AND b.status = ?';
            params.push(status);
        }
        if (date_from) {
            sql += ' AND b.pickup_date >= ?';
            params.push(date_from);
        }
        if (date_to) {
            sql += ' AND b.pickup_date <= ?';
            params.push(date_to);
        }

        sql += ' ORDER BY b.pickup_date DESC, b.pickup_time DESC LIMIT ? OFFSET ?';
        params.push(parseInt(limit), parseInt(offset));

        const bookings = await database.all(sql, params);

        res.json({ bookings, count: bookings.length });
    } catch (error) {
        console.error('Get all bookings error:', error);
        res.status(500).json({ error: 'Failed to fetch bookings' });
    }
});

// Admin: Update booking status
router.patch('/:id/status', auth, isAdmin, async (req, res) => {
    try {
        const { status } = req.body;
        const validStatuses = ['pending', 'confirmed', 'assigned', 'in_progress', 'completed', 'cancelled'];

        if (!validStatuses.includes(status)) {
            return res.status(400).json({ error: 'Invalid status' });
        }

        await database.run(
            'UPDATE bookings SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?',
            [status, req.params.id]
        );

        res.json({ message: 'Booking status updated' });
    } catch (error) {
        console.error('Update status error:', error);
        res.status(500).json({ error: 'Failed to update status' });
    }
});

// Cancel booking
router.delete('/:id', auth, async (req, res) => {
    try {
        const booking = await database.get(
            'SELECT user_id, status FROM bookings WHERE id = ?',
            [req.params.id]
        );

        if (!booking) {
            return res.status(404).json({ error: 'Booking not found' });
        }

        if (booking.user_id !== req.user.id && req.user.role !== 'admin') {
            return res.status(403).json({ error: 'Unauthorized' });
        }

        if (booking.status === 'completed' || booking.status === 'cancelled') {
            return res.status(400).json({ error: 'Cannot cancel this booking' });
        }

        await database.run(
            'UPDATE bookings SET status = \'cancelled\', updated_at = CURRENT_TIMESTAMP WHERE id = ?',
            [req.params.id]
        );

        res.json({ message: 'Booking cancelled successfully' });
    } catch (error) {
        console.error('Cancel booking error:', error);
        res.status(500).json({ error: 'Failed to cancel booking' });
    }
});

module.exports = router;
