const { Ticket, TicketItem, Commande, CommandeItem, Client, Utilisateur, Menu, sequelize } = require('../models/associations');
const { Op } = require('sequelize');
const PDFDocument = require('pdfkit');
const fs = require('fs').promises;
const path = require('path');

class TicketController {
    // Générer un numéro de ticket unique
    async generateTicketNumber() {
        const date = new Date();
        const year = date.getFullYear().toString().substr(-2);
        const month = (date.getMonth() + 1).toString().padStart(2, '0');
        const day = date.getDate().toString().padStart(2, '0');
        
        const prefix = `T${year}${month}${day}`;
        
        // Trouver le dernier ticket du jour
        const lastTicket = await Ticket.findOne({
            where: {
                numero_ticket: {
                    [Op.like]: `${prefix}%`
                }
            },
            order: [['numero_ticket', 'DESC']]
        });
        
        let sequence = 1;
        if (lastTicket) {
            const lastSequence = parseInt(lastTicket.numero_ticket.substr(-4));
            sequence = lastSequence + 1;
        }
        
        return `${prefix}${sequence.toString().padStart(4, '0')}`;
    }

    // Calculer les montants avec TVA
    calculateAmounts(items, taux_tva = 20, remise = 0) {
        let montant_ht = 0;
        
        items.forEach(item => {
            const prix_unitaire_ht = item.prix_unitaire_ttc / (1 + taux_tva / 100);
            const montant_item_ht = prix_unitaire_ht * item.quantite - (item.remise_unitaire || 0);
            montant_ht += montant_item_ht;
        });
        
        montant_ht -= remise;
        const montant_tva = montant_ht * (taux_tva / 100);
        const montant_ttc = montant_ht + montant_tva;
        
        return {
            montant_ht: Math.max(0, montant_ht),
            montant_tva: Math.max(0, montant_tva),
            montant_ttc: Math.max(0, montant_ttc)
        };
    }

    // Obtenir tous les tickets avec pagination et filtres
    async getAllTickets(req, res) {
        try {
            const {
                page = 1,
                limit = 10,
                search = '',
                statut,
                mode_paiement,
                date_debut,
                date_fin,
                client_id,
                utilisateur_id,
                sort_by = 'date_emission',
                sort_order = 'DESC'
            } = req.query;

            const offset = (parseInt(page) - 1) * parseInt(limit);
            
            const whereConditions = {};
            
            if (search) {
                whereConditions[Op.or] = [
                    { numero_ticket: { [Op.like]: `%${search}%` } },
                    { '$Client.nom$': { [Op.like]: `%${search}%` } },
                    { '$Client.prenom$': { [Op.like]: `%${search}%` } }
                ];
            }
            
            if (statut) whereConditions.statut = statut;
            if (mode_paiement) whereConditions.mode_paiement = mode_paiement;
            if (client_id) whereConditions.client_id = client_id;
            if (utilisateur_id) whereConditions.utilisateur_id = utilisateur_id;
            
            if (date_debut || date_fin) {
                whereConditions.date_emission = {};
                if (date_debut) whereConditions.date_emission[Op.gte] = new Date(date_debut);
                if (date_fin) whereConditions.date_emission[Op.lte] = new Date(date_fin);
            }

            const validSortFields = ['numero_ticket', 'date_emission', 'montant_ttc', 'statut'];
            const sortField = validSortFields.includes(sort_by) ? sort_by : 'date_emission';
            const sortOrder = ['ASC', 'DESC'].includes(sort_order.toUpperCase()) ? 
                              sort_order.toUpperCase() : 'DESC';

            const { count, rows } = await Ticket.findAndCountAll({
                where: whereConditions,
                include: [
                    {
                        model: Client,
                        attributes: ['id', 'nom', 'prenom', 'email', 'telephone'],
                        required: false
                    },
                    {
                        model: Utilisateur,
                        attributes: ['id', 'nom', 'prenom'],
                        required: true
                    },
                    {
                        model: Commande,
                        attributes: ['id', 'numero_commande'],
                        required: true
                    },
                    {
                        model: TicketItem,
                        attributes: ['id', 'nom_item', 'quantite', 'montant_ttc'],
                        required: false
                    }
                ],
                order: [[sortField, sortOrder]],
                limit: parseInt(limit),
                offset: offset,
                distinct: true
            });

            res.json({
                success: true,
                data: {
                    tickets: rows,
                    pagination: {
                        currentPage: parseInt(page),
                        totalPages: Math.ceil(count / parseInt(limit)),
                        totalItems: count,
                        itemsPerPage: parseInt(limit)
                    }
                }
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la récupération des tickets',
                error: error.message
            });
        }
    }

    // Obtenir un ticket par ID
    async getTicketById(req, res) {
        try {
            const { id } = req.params;

            const ticket = await Ticket.findByPk(id, {
                include: [
                    {
                        model: Client,
                        required: false
                    },
                    {
                        model: Utilisateur,
                        attributes: ['id', 'nom', 'prenom', 'email']
                    },
                    {
                        model: Commande,
                        include: [{
                            model: CommandeItem,
                            include: [{ model: Menu, attributes: ['nom', 'description'] }]
                        }]
                    },
                    {
                        model: TicketItem,
                        required: false
                    }
                ]
            });

            if (!ticket) {
                return res.status(404).json({
                    success: false,
                    message: 'Ticket non trouvé'
                });
            }

            res.json({
                success: true,
                data: ticket
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la récupération du ticket',
                error: error.message
            });
        }
    }

    // Créer un ticket depuis une commande
    async createTicketFromOrder(req, res) {
        const transaction = await sequelize.transaction();
        
        try {
            const {
                commande_id,
                client_id,
                utilisateur_id,
                mode_paiement = 'especes',
                taux_tva = 20,
                remise = 0,
                notes
            } = req.body;

            // Vérifier que la commande existe
            const commande = await Commande.findByPk(commande_id, {
                include: [{
                    model: CommandeItem,
                    include: [{ model: Menu }]
                }],
                transaction
            });

            if (!commande) {
                await transaction.rollback();
                return res.status(404).json({
                    success: false,
                    message: 'Commande non trouvée'
                });
            }

            if (commande.CommandeItems.length === 0) {
                await transaction.rollback();
                return res.status(400).json({
                    success: false,
                    message: 'La commande ne contient aucun item'
                });
            }

            // Générer le numéro de ticket
            const numero_ticket = await this.generateTicketNumber();

            // Calculer les montants
            const amounts = this.calculateAmounts(
                commande.CommandeItems.map(item => ({
                    prix_unitaire_ttc: parseFloat(item.prix_unitaire),
                    quantite: item.quantite,
                    remise_unitaire: 0
                })),
                taux_tva,
                remise
            );

            // Récupérer les données client si fourni
            let donnees_client = null;
            if (client_id) {
                const client = await Client.findByPk(client_id, { transaction });
                if (client) {
                    donnees_client = {
                        nom: client.nom,
                        prenom: client.prenom,
                        email: client.email,
                        telephone: client.telephone,
                        adresse: client.adresse
                    };
                }
            }

            // Créer le ticket
            const ticket = await Ticket.create({
                numero_ticket,
                commande_id,
                client_id,
                utilisateur_id,
                montant_ht: amounts.montant_ht,
                montant_tva: amounts.montant_tva,
                montant_ttc: amounts.montant_ttc,
                remise,
                taux_tva,
                mode_paiement,
                statut: 'emis',
                date_emission: new Date(),
                notes,
                donnees_client
            }, { transaction });

            // Créer les items du ticket
            const ticketItems = await Promise.all(
                commande.CommandeItems.map(async (item) => {
                    const prix_unitaire_ht = parseFloat(item.prix_unitaire) / (1 + taux_tva / 100);
                    const montant_ht = prix_unitaire_ht * item.quantite;
                    const montant_tva = montant_ht * (taux_tva / 100);
                    const montant_ttc = montant_ht + montant_tva;

                    return TicketItem.create({
                        ticket_id: ticket.id,
                        commande_item_id: item.id,
                        nom_item: item.Menu ? item.Menu.nom : `Item ${item.id}`,
                        description: item.notes,
                        quantite: item.quantite,
                        prix_unitaire_ht,
                        prix_unitaire_ttc: parseFloat(item.prix_unitaire),
                        montant_ht,
                        montant_tva,
                        montant_ttc,
                        taux_tva,
                        remise_unitaire: 0
                    }, { transaction });
                })
            );

            await transaction.commit();

            // Récupérer le ticket complet
            const ticketComplet = await Ticket.findByPk(ticket.id, {
                include: [
                    { model: Client },
                    { model: Utilisateur, attributes: ['nom', 'prenom'] },
                    { model: Commande },
                    { model: TicketItem }
                ]
            });

            res.status(201).json({
                success: true,
                message: 'Ticket créé avec succès',
                data: ticketComplet
            });
        } catch (error) {
            await transaction.rollback();
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la création du ticket',
                error: error.message
            });
        }
    }

    // Mettre à jour le statut d'un ticket
    async updateTicketStatus(req, res) {
        try {
            const { id } = req.params;
            const { statut, date_paiement, notes } = req.body;

            const ticket = await Ticket.findByPk(id);
            if (!ticket) {
                return res.status(404).json({
                    success: false,
                    message: 'Ticket non trouvé'
                });
            }

            const updateData = { statut };
            
            if (statut === 'paye' && date_paiement) {
                updateData.date_paiement = new Date(date_paiement);
            }
            
            if (notes !== undefined) {
                updateData.notes = notes;
            }

            await ticket.update(updateData);

            res.json({
                success: true,
                message: 'Statut du ticket mis à jour avec succès',
                data: ticket
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la mise à jour du statut',
                error: error.message
            });
        }
    }

    // Obtenir les statistiques des tickets
    async getTicketStats(req, res) {
        try {
            const { date_debut, date_fin } = req.query;
            
            const whereConditions = {};
            if (date_debut || date_fin) {
                whereConditions.date_emission = {};
                if (date_debut) whereConditions.date_emission[Op.gte] = new Date(date_debut);
                if (date_fin) whereConditions.date_emission[Op.lte] = new Date(date_fin);
            }

            const [
                total,
                emis,
                payes,
                annules,
                totalRevenue,
                payedRevenue
            ] = await Promise.all([
                Ticket.count({ where: whereConditions }),
                Ticket.count({ where: { ...whereConditions, statut: 'emis' } }),
                Ticket.count({ where: { ...whereConditions, statut: 'paye' } }),
                Ticket.count({ where: { ...whereConditions, statut: 'annule' } }),
                Ticket.sum('montant_ttc', { where: whereConditions }),
                Ticket.sum('montant_ttc', { 
                    where: { ...whereConditions, statut: 'paye' } 
                })
            ]);

            // Statistiques par mode de paiement
            const paymentStats = await Ticket.findAll({
                attributes: [
                    'mode_paiement',
                    [sequelize.fn('COUNT', sequelize.col('id')), 'count'],
                    [sequelize.fn('SUM', sequelize.col('montant_ttc')), 'total']
                ],
                where: { ...whereConditions, statut: 'paye' },
                group: ['mode_paiement']
            });

            res.json({
                success: true,
                data: {
                    total,
                    emis,
                    payes,
                    annules,
                    totalRevenue: parseFloat(totalRevenue || 0),
                    payedRevenue: parseFloat(payedRevenue || 0),
                    paymentMethods: paymentStats.map(stat => ({
                        mode: stat.mode_paiement,
                        count: parseInt(stat.dataValues.count),
                        total: parseFloat(stat.dataValues.total || 0)
                    }))
                }
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la récupération des statistiques',
                error: error.message
            });
        }
    }

    // Générer un PDF pour un ticket
    async generatePDF(req, res) {
        try {
            const { id } = req.params;

            const ticket = await Ticket.findByPk(id, {
                include: [
                    { model: Client },
                    { model: Utilisateur, attributes: ['nom', 'prenom'] },
                    { model: TicketItem }
                ]
            });

            if (!ticket) {
                return res.status(404).json({
                    success: false,
                    message: 'Ticket non trouvé'
                });
            }

            // Créer le dossier s'il n'existe pas
            const pdfDir = path.join(__dirname, '../uploads/tickets');
            await fs.mkdir(pdfDir, { recursive: true });

            const pdfPath = path.join(pdfDir, `ticket_${ticket.numero_ticket}.pdf`);

            // Créer le document PDF
            const doc = new PDFDocument();
            doc.pipe(fs.createWriteStream(pdfPath));

            // En-tête
            doc.fontSize(20).text('TICKET DE CAISSE', { align: 'center' });
            doc.moveDown();
            
            doc.fontSize(12).text(`Numéro: ${ticket.numero_ticket}`, { align: 'left' });
            doc.text(`Date: ${ticket.date_emission.toLocaleDateString('fr-FR')}`, { align: 'left' });
            doc.text(`Serveur: ${ticket.Utilisateur.nom} ${ticket.Utilisateur.prenom}`, { align: 'left' });
            
            if (ticket.Client) {
                doc.text(`Client: ${ticket.Client.nom} ${ticket.Client.prenom}`, { align: 'left' });
            }
            
            doc.moveDown();

            // Détail des items
            doc.text('DÉTAIL:', { underline: true });
            doc.moveDown(0.5);

            ticket.TicketItems.forEach(item => {
                doc.text(`${item.nom_item} x${item.quantite}`, { continued: true });
                doc.text(`${parseFloat(item.montant_ttc).toFixed(2)}€`, { align: 'right' });
            });

            doc.moveDown();

            // Totaux
            doc.text(`Montant HT: ${parseFloat(ticket.montant_ht).toFixed(2)}€`, { align: 'right' });
            doc.text(`TVA (${ticket.taux_tva}%): ${parseFloat(ticket.montant_tva).toFixed(2)}€`, { align: 'right' });
            if (ticket.remise > 0) {
                doc.text(`Remise: ${parseFloat(ticket.remise).toFixed(2)}€`, { align: 'right' });
            }
                        doc.fontSize(14).text(`TOTAL TTC: ${parseFloat(ticket.montant_ttc).toFixed(2)}€`, { align: 'right' });
            
            doc.moveDown();
            doc.fontSize(12).text(`Mode de paiement: ${ticket.mode_paiement.toUpperCase()}`, { align: 'left' });
            doc.text(`Statut: ${ticket.statut.toUpperCase()}`, { align: 'left' });

            if (ticket.notes) {
                doc.moveDown();
                doc.text(`Notes: ${ticket.notes}`, { align: 'left' });
            }

            // Pied de page
            doc.moveDown(2);
            doc.fontSize(10).text('Merci de votre visite !', { align: 'center' });
            doc.text('À bientôt dans notre restaurant', { align: 'center' });

            doc.end();

            // Mettre à jour le chemin du PDF dans la base
            await ticket.update({ facture_pdf: `tickets/ticket_${ticket.numero_ticket}.pdf` });

            res.json({
                success: true,
                message: 'PDF généré avec succès',
                data: {
                    pdf_path: `/uploads/tickets/ticket_${ticket.numero_ticket}.pdf`,
                    ticket_id: ticket.id
                }
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la génération du PDF',
                error: error.message
            });
        }
    }

    // Supprimer un ticket
    async deleteTicket(req, res) {
        try {
            const { id } = req.params;

            const ticket = await Ticket.findByPk(id);
            if (!ticket) {
                return res.status(404).json({
                    success: false,
                    message: 'Ticket non trouvé'
                });
            }

            // Vérifier si le ticket peut être supprimé
            if (ticket.statut === 'paye') {
                return res.status(400).json({
                    success: false,
                    message: 'Impossible de supprimer un ticket payé. Vous pouvez l\'annuler.'
                });
            }

            // Supprimer le fichier PDF s'il existe
            if (ticket.facture_pdf) {
                const pdfPath = path.join(__dirname, '../uploads/', ticket.facture_pdf);
                try {
                    await fs.unlink(pdfPath);
                } catch (err) {
                    console.log('PDF file not found or already deleted');
                }
            }

            await ticket.destroy();

            res.json({
                success: true,
                message: 'Ticket supprimé avec succès'
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la suppression du ticket',
                error: error.message
            });
        }
    }

    // Dupliquer un ticket
    async duplicateTicket(req, res) {
        const transaction = await sequelize.transaction();
        
        try {
            const { id } = req.params;
            const { utilisateur_id, notes } = req.body;

            const originalTicket = await Ticket.findByPk(id, {
                include: [{ model: TicketItem }],
                transaction
            });

            if (!originalTicket) {
                await transaction.rollback();
                return res.status(404).json({
                    success: false,
                    message: 'Ticket original non trouvé'
                });
            }

            // Générer un nouveau numéro de ticket
            const numero_ticket = await this.generateTicketNumber();

            // Créer le nouveau ticket
            const newTicket = await Ticket.create({
                numero_ticket,
                commande_id: originalTicket.commande_id,
                client_id: originalTicket.client_id,
                utilisateur_id: utilisateur_id || originalTicket.utilisateur_id,
                montant_ht: originalTicket.montant_ht,
                montant_tva: originalTicket.montant_tva,
                montant_ttc: originalTicket.montant_ttc,
                remise: originalTicket.remise,
                taux_tva: originalTicket.taux_tva,
                mode_paiement: originalTicket.mode_paiement,
                statut: 'brouillon',
                date_emission: new Date(),
                notes: notes || `Copie du ticket ${originalTicket.numero_ticket}`,
                donnees_client: originalTicket.donnees_client
            }, { transaction });

            // Dupliquer les items
            const newItems = await Promise.all(
                originalTicket.TicketItems.map(item =>
                    TicketItem.create({
                        ticket_id: newTicket.id,
                        commande_item_id: item.commande_item_id,
                        nom_item: item.nom_item,
                        description: item.description,
                        quantite: item.quantite,
                        prix_unitaire_ht: item.prix_unitaire_ht,
                        prix_unitaire_ttc: item.prix_unitaire_ttc,
                        montant_ht: item.montant_ht,
                        montant_tva: item.montant_tva,
                        montant_ttc: item.montant_ttc,
                        taux_tva: item.taux_tva,
                        remise_unitaire: item.remise_unitaire
                    }, { transaction })
                )
            );

            await transaction.commit();

            // Récupérer le ticket complet
            const ticketComplet = await Ticket.findByPk(newTicket.id, {
                include: [
                    { model: Client },
                    { model: Utilisateur, attributes: ['nom', 'prenom'] },
                    { model: TicketItem }
                ]
            });

            res.status(201).json({
                success: true,
                message: 'Ticket dupliqué avec succès',
                data: ticketComplet
            });
        } catch (error) {
            await transaction.rollback();
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la duplication du ticket',
                error: error.message
            });
        }
    }

    // Recherche avancée de tickets
    async searchTickets(req, res) {
        try {
            const {
                numero_ticket,
                client_nom,
                montant_min,
                montant_max,
                date_debut,
                date_fin,
                statut,
                mode_paiement,
                limit = 50
            } = req.query;

            const whereConditions = {};
            const clientWhereConditions = {};

            if (numero_ticket) {
                whereConditions.numero_ticket = { [Op.like]: `%${numero_ticket}%` };
            }

            if (client_nom) {
                clientWhereConditions[Op.or] = [
                    { nom: { [Op.like]: `%${client_nom}%` } },
                    { prenom: { [Op.like]: `%${client_nom}%` } }
                ];
            }

            if (montant_min || montant_max) {
                whereConditions.montant_ttc = {};
                if (montant_min) whereConditions.montant_ttc[Op.gte] = parseFloat(montant_min);
                if (montant_max) whereConditions.montant_ttc[Op.lte] = parseFloat(montant_max);
            }

            if (date_debut || date_fin) {
                whereConditions.date_emission = {};
                if (date_debut) whereConditions.date_emission[Op.gte] = new Date(date_debut);
                if (date_fin) whereConditions.date_emission[Op.lte] = new Date(date_fin);
            }

            if (statut) whereConditions.statut = statut;
            if (mode_paiement) whereConditions.mode_paiement = mode_paiement;

            const tickets = await Ticket.findAll({
                where: whereConditions,
                include: [
                    {
                        model: Client,
                        where: Object.keys(clientWhereConditions).length > 0 ? clientWhereConditions : undefined,
                        required: false,
                        attributes: ['id', 'nom', 'prenom', 'email']
                    },
                    {
                        model: Utilisateur,
                        attributes: ['id', 'nom', 'prenom']
                    }
                ],
                order: [['date_emission', 'DESC']],
                limit: parseInt(limit)
            });

            res.json({
                success: true,
                data: {
                    tickets,
                    count: tickets.length
                }
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la recherche',
                error: error.message
            });
        }
    }
}

module.exports = new TicketController();

