import { Router } from 'express';
import { prisma } from '../../lib/prisma.js';
import { z } from 'zod';
import jwt from 'jsonwebtoken';
import QRCode from 'qrcode';
const router = Router();
// Validation schemas
const createBookingSchema = z.object({
    showtimeId: z.number(),
    seatLabels: z.array(z.string()),
    paymentMethod: z.string().optional().default('card')
});
// Middleware to verify JWT token
const verifyToken = (req, res, next) => {
    const token = req.headers.authorization?.replace('Bearer ', '');
    if (!token) {
        return res.status(401).json({
            success: false,
            message: 'No token provided'
        });
    }
    try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET || 'fallback-secret');
        req.userId = decoded.userId;
        next();
    }
    catch (error) {
        return res.status(401).json({
            success: false,
            message: 'Invalid token'
        });
    }
};
// Create a new booking
router.post('/', verifyToken, async (req, res) => {
    try {
        const { showtimeId, seatLabels, paymentMethod } = createBookingSchema.parse(req.body);
        const userId = req.userId;
        // Verify showtime exists
        const showtime = await prisma.showtime.findUnique({
            where: { id: showtimeId },
            include: {
                movie: true,
                hall: true,
                bookings: {
                    select: {
                        seatLabel: true
                    }
                }
            }
        });
        if (!showtime) {
            return res.status(404).json({
                success: false,
                message: 'Showtime not found'
            });
        }
        // Check if showtime is in the future
        if (showtime.showDate < new Date()) {
            return res.status(400).json({
                success: false,
                message: 'Cannot book for past showtimes'
            });
        }
        // Check if seats are available
        const bookedSeats = new Set(showtime.bookings.map(booking => booking.seatLabel));
        const unavailableSeats = seatLabels.filter(seat => bookedSeats.has(seat));
        if (unavailableSeats.length > 0) {
            return res.status(400).json({
                success: false,
                message: `Seats ${unavailableSeats.join(', ')} are already booked`
            });
        }
        // Verify seats exist in the hall
        const hallSeats = await prisma.seat.findMany({
            where: {
                hallId: showtime.hallId,
                label: { in: seatLabels }
            }
        });
        if (hallSeats.length !== seatLabels.length) {
            return res.status(400).json({
                success: false,
                message: 'Some seats do not exist in this hall'
            });
        }
        // Calculate total amount
        const totalAmount = seatLabels.length * Number(showtime.basePrice);
        // Create bookings for each seat
        const bookings = [];
        for (const seatLabel of seatLabels) {
            const booking = await prisma.booking.create({
                data: {
                    userId,
                    showtimeId,
                    seatLabel,
                    amount: showtime.basePrice,
                    paymentStatus: 'completed' // For demo purposes, assume payment is always successful
                }
            });
            bookings.push(booking);
        }
        // Generate QR code for the booking
        const bookingIds = bookings.map(b => b.id).join(',');
        const qrData = {
            bookingIds,
            showtimeId,
            movieTitle: showtime.movie.title,
            showDate: showtime.showDate,
            seats: seatLabels,
            totalAmount
        };
        const qrCodeUrl = await QRCode.toDataURL(JSON.stringify(qrData));
        // Update bookings with QR code
        await prisma.booking.updateMany({
            where: {
                id: { in: bookings.map(b => b.id) }
            },
            data: {
                qrCode: qrCodeUrl
            }
        });
        res.status(201).json({
            success: true,
            message: 'Booking created successfully',
            data: {
                bookings: bookings.map(booking => ({
                    ...booking,
                    qrCode: qrCodeUrl
                })),
                totalAmount,
                movie: showtime.movie,
                showtime: {
                    id: showtime.id,
                    showDate: showtime.showDate,
                    hall: showtime.hall
                },
                seats: seatLabels
            }
        });
    }
    catch (error) {
        console.error('Error creating booking:', error);
        if (error instanceof z.ZodError) {
            return res.status(400).json({
                success: false,
                message: 'Validation error',
                errors: error.issues
            });
        }
        res.status(500).json({
            success: false,
            message: 'Internal server error'
        });
    }
});
// Get user's bookings
router.get('/my-bookings', verifyToken, async (req, res) => {
    try {
        const userId = req.userId;
        const bookings = await prisma.booking.findMany({
            where: { userId },
            include: {
                showtime: {
                    include: {
                        movie: {
                            select: {
                                id: true,
                                title: true,
                                posterUrl: true,
                                genre: true
                            }
                        },
                        hall: {
                            select: {
                                id: true,
                                name: true
                            }
                        }
                    }
                }
            },
            orderBy: {
                createdAt: 'desc'
            }
        });
        // Group bookings by showtime
        const groupedBookings = bookings.reduce((acc, booking) => {
            const key = booking.showtimeId;
            if (!acc[key]) {
                acc[key] = {
                    showtime: booking.showtime,
                    seats: [],
                    totalAmount: 0,
                    bookingIds: [],
                    qrCode: booking.qrCode
                };
            }
            acc[key].seats.push(booking.seatLabel);
            acc[key].totalAmount += Number(booking.amount);
            acc[key].bookingIds.push(booking.id);
        }, {});
        const bookingGroups = Object.values(groupedBookings);
        res.json({
            success: true,
            data: { bookings: bookingGroups }
        });
    }
    catch (error) {
        console.error('Error fetching user bookings:', error);
        res.status(500).json({
            success: false,
            message: 'Internal server error'
        });
    }
});
// Get booking by ID
router.get('/:id', verifyToken, async (req, res) => {
    try {
        const bookingId = parseInt(req.params.id);
        const userId = req.userId;
        if (isNaN(bookingId)) {
            return res.status(400).json({
                success: false,
                message: 'Invalid booking ID'
            });
        }
        const booking = await prisma.booking.findFirst({
            where: {
                id: bookingId,
                userId // Ensure user can only access their own bookings
            },
            include: {
                showtime: {
                    include: {
                        movie: true,
                        hall: true
                    }
                }
            }
        });
        if (!booking) {
            return res.status(404).json({
                success: false,
                message: 'Booking not found'
            });
        }
        res.json({
            success: true,
            data: { booking }
        });
    }
    catch (error) {
        console.error('Error fetching booking:', error);
        res.status(500).json({
            success: false,
            message: 'Internal server error'
        });
    }
});
// Cancel booking
router.delete('/:id', verifyToken, async (req, res) => {
    try {
        const bookingId = parseInt(req.params.id);
        const userId = req.userId;
        if (isNaN(bookingId)) {
            return res.status(400).json({
                success: false,
                message: 'Invalid booking ID'
            });
        }
        const booking = await prisma.booking.findFirst({
            where: {
                id: bookingId,
                userId
            },
            include: {
                showtime: true
            }
        });
        if (!booking) {
            return res.status(404).json({
                success: false,
                message: 'Booking not found'
            });
        }
        // Check if booking can be cancelled (e.g., not within 2 hours of showtime)
        const twoHoursBefore = new Date(booking.showtime.showDate.getTime() - 2 * 60 * 60 * 1000);
        if (new Date() > twoHoursBefore) {
            return res.status(400).json({
                success: false,
                message: 'Cannot cancel booking within 2 hours of showtime'
            });
        }
        await prisma.booking.delete({
            where: { id: bookingId }
        });
        res.json({
            success: true,
            message: 'Booking cancelled successfully'
        });
    }
    catch (error) {
        console.error('Error cancelling booking:', error);
        res.status(500).json({
            success: false,
            message: 'Internal server error'
        });
    }
});
export default router;
