const express = require('express');
const { Book, Order, OrderItem, sequelize, Review, User } = require('../models');
const { authenticateToken, isAdmin } = require('../middleware/auth');
const { Op } = require('sequelize');
const router = express.Router();

// Get Bestselling Books
router.get('/bestsellers', async (req, res) => {
    try {
        const bestSellers = await OrderItem.findAll({
            attributes: [
                'book_id',
                [sequelize.fn('SUM', sequelize.col('quantity')), 'total_sold']
            ],
            include: [{
                model: Book
            }, {
                model: Order,
                attributes: [],
                where: {
                    status: {
                        [Op.in]: [
                            'paid', 'shipped', 'delivered', 'completed', 'processing',
                            'Paid', 'Shipped', 'Delivered', 'Completed', 'Processing',
                            'selesai', 'diterima', 'dikirim', 'diproses'
                        ]
                    }
                }
            }],
            group: ['book_id', 'Book.id', 'Book.title', 'Book.price', 'Book.originalPrice', 'Book.author', 'Book.image', 'Book.category', 'Book.description', 'Book.stock', 'Book.isbn', 'Book.publisher', 'Book.publish_date', 'Book.rating', 'Book.discount', 'Book.tags', 'Book.created_at', 'Book.updated_at'], // Group by all Book fields
            order: [[sequelize.literal('total_sold'), 'DESC']],
            limit: 5 // Top 5
        });

        const formattedBooks = bestSellers.map(item => {
            const book = item.Book.toJSON();
            return {
                ...book,
                sold: parseInt(item.dataValues.total_sold)
            };
        });

        res.json(formattedBooks);
    } catch (error) {
        console.error("Bestsellers error:", error);
        res.status(500).json({ message: 'Server error', error: error.message });
    }
});

// Get All Books (with filtering/search)
router.get('/', async (req, res) => {
    try {
        res.set('Cache-Control', 'no-store'); // Prevent caching
        const { search, category, minPrice, maxPrice } = req.query;
        let where = {};

        if (search) {
            where.title = { [Op.like]: `%${search}%` };
        }
        if (category) {
            where.category = category;
        }
        if (minPrice || maxPrice) {
            where.price = {};
            if (minPrice) where.price[Op.gte] = minPrice;
            if (maxPrice) where.price[Op.lte] = maxPrice;
        }


        const books = await Book.findAll({ where });
        res.json(books);
    } catch (error) {
        res.status(500).json({ message: 'Server error', error: error.message });
    }
});

// Get Single Book with Reviews and Sold Count
router.get('/:id', async (req, res) => {
    try {
        const book = await Book.findByPk(req.params.id, {
            include: [
                {
                    model: Review,
                    include: [{ model: User, attributes: ['id', 'username', 'email', ['image', 'avatar']] }]
                }
            ]
        });

        if (!book) return res.status(404).json({ message: 'Book not found' });

        // Calculate sold count
        const totalSold = await OrderItem.sum('quantity', {
            where: { book_id: req.params.id },
            include: [{
                model: Order,
                where: {
                    status: { [Op.in]: ['paid', 'shipped', 'delivered', 'completed'] }
                }
            }]
        });

        const bookData = book.toJSON();
        bookData.sold = totalSold || 0;

        // Calculate average rating
        if (bookData.Reviews && bookData.Reviews.length > 0) {
            const sumRating = bookData.Reviews.reduce((acc, r) => acc + r.rating, 0);
            bookData.rating = (sumRating / bookData.Reviews.length).toFixed(1);
        } else {
            bookData.rating = 0;
        }

        res.json(bookData);
    } catch (error) {
        console.error("Error fetching book details:", error);
        res.status(500).json({ message: 'Server error' });
    }
});

// Create Review
router.post('/:id/reviews', authenticateToken, async (req, res) => {
    try {
        const { rating, comment } = req.body;
        const bookId = req.params.id;
        const userId = req.user.id;

        // Verify if user purchased the book (Optional, but good for "Verified Purchase")
        const hasPurchased = await OrderItem.findOne({
            where: { book_id: bookId },
            include: [{
                model: Order,
                where: {
                    user_id: userId,
                    status: { [Op.in]: ['completed', 'delivered', 'selesai', 'diterima', 'shipped', 'dikirim'] } // Allow varying completed statuses
                }
            }]
        });

        if (!hasPurchased) {
            // For now, let's allow it but maybe warn or just strictly block?
            // User request: "tolong agar user bisa review buku setelah barang sampai dan menekan pesanan diterima"
            // So we should enforce strict check or at least check for 'completed' status.
            return res.status(403).json({ message: 'You can only review books you have purchased and received.' });
        }

        // Check if already reviewed
        const existingReview = await Review.findOne({
            where: {
                user_id: userId,
                book_id: bookId
            }
        });

        if (existingReview) {
            return res.status(400).json({ message: 'You have already reviewed this book.' });
        }

        const review = await Review.create({
            user_id: userId,
            book_id: bookId,
            rating,
            comment
        });

        // Calculate and update average rating for the book
        const allReviews = await Review.findAll({ where: { book_id: bookId } });
        const avgRating = allReviews.reduce((acc, r) => acc + r.rating, 0) / allReviews.length;

        await Book.update(
            { rating: parseFloat(avgRating.toFixed(1)) },
            { where: { id: bookId } }
        );

        // Fetch fresh review with user data to return
        const fullReview = await Review.findByPk(review.id, {
            include: [{ model: User, attributes: ['id', 'username', ['image', 'avatar']] }]
        });

        res.status(201).json(fullReview);
    } catch (error) {
        console.error("Review error:", error);
        res.status(500).json({ message: 'Server error' });
    }
});

const multer = require('multer');
const path = require('path');
const fs = require('fs');

// Configure Multer
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        const dir = 'uploads/buku';
        if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir, { recursive: true });
        }
        cb(null, dir);
    },
    filename: function (req, file, cb) {
        cb(null, Date.now() + '-' + file.originalname.replace(/\s+/g, '-'));
    }
});

const upload = multer({ storage: storage });

// Admin: Create Book
router.post('/', authenticateToken, isAdmin, upload.single('image'), async (req, res) => {
    try {
        const bookData = req.body;

        // Handle Image Upload
        if (req.file) {
            // Construct URL
            const protocol = req.protocol;
            const host = req.get('host');
            bookData.image = `${protocol}://${host}/uploads/buku/${req.file.filename}`;
        }

        // Handle Tags parsing for FormData
        if (typeof bookData.tags === 'string') {
            try {
                bookData.tags = JSON.parse(bookData.tags);
            } catch (e) {
                // Ignore if not JSON string, maybe just comma separated? Use as is or split?
                // If it's "a,b" and we want array:
                if (bookData.tags.includes(',')) {
                    bookData.tags = bookData.tags.split(',').map(t => t.trim());
                }
            }
        }

        const book = await Book.create(bookData);
        res.status(201).json(book);
    } catch (error) {
        res.status(500).json({ message: 'Server error', error: error.message });
    }
});

// Admin: Update Book
router.put('/:id', authenticateToken, isAdmin, upload.single('image'), async (req, res) => {
    try {
        const book = await Book.findByPk(req.params.id);
        if (!book) return res.status(404).json({ message: 'Book not found' });

        const bookData = req.body;

        // Handle Image Upload
        if (req.file) {
            const protocol = req.protocol;
            const host = req.get('host');
            bookData.image = `${protocol}://${host}/uploads/buku/${req.file.filename}`;
        }

        // Handle Tags parsing for FormData
        if (typeof bookData.tags === 'string') {
            try {
                bookData.tags = JSON.parse(bookData.tags);
            } catch (e) {
                if (bookData.tags.includes(',')) {
                    bookData.tags = bookData.tags.split(',').map(t => t.trim());
                }
            }
        }

        await book.update(bookData);
        res.json(book);
    } catch (error) {
        res.status(500).json({ message: 'Server error' });
    }
});

// Admin: Delete Book
router.delete('/:id', authenticateToken, isAdmin, async (req, res) => {
    try {
        const book = await Book.findByPk(req.params.id);
        if (!book) return res.status(404).json({ message: 'Book not found' });
        await book.destroy();
        res.json({ message: 'Book deleted' });
    } catch (error) {
        res.status(500).json({ message: 'Server error' });
    }
});

module.exports = router;
