const { Op } = require('sequelize');
const { Utilisateur, sequelize } = require('../models/associations');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const multer = require('multer');
const path = require('path');
const fs = require('fs').promises;

// Configuration Multer pour upload de photos
const storage = multer.diskStorage({
    destination: async (req, file, cb) => {
        const uploadDir = path.join(__dirname, '../uploads/utilisateurs');
        try {
            await fs.mkdir(uploadDir, { recursive: true });
            cb(null, uploadDir);
        } catch (error) {
            cb(error);
        }
    },
    filename: (req, file, cb) => {
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
        cb(null, 'user-' + uniqueSuffix + path.extname(file.originalname));
    }
});

const upload = multer({
    storage: storage,
    limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
    fileFilter: (req, file, cb) => {
        const allowedTypes = /jpeg|jpg|png|gif/;
        const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
        const mimetype = allowedTypes.test(file.mimetype);
        
        if (mimetype && extname) {
            return cb(null, true);
        } else {
            cb(new Error('Seules les images sont autorisées'));
        }
    }
});

class UtilisateurController {
    // Lister tous les utilisateurs
    async getAllUtilisateurs(req, res) {
        try {
            const { 
                page = 1, 
                limit = 10, 
                role, 
                statut, 
                search,
                sort_by = 'cree_le',
                sort_order = 'DESC'
            } = req.query;

            const offset = (page - 1) * limit;
            const whereConditions = {};

            // Filtres
            if (role) whereConditions.role = role;
            if (statut) whereConditions.statut = statut;
            if (search) {
                whereConditions[Op.or] = [
                    { nom: { [Op.like]: `%${search}%` } },
                    { prenom: { [Op.like]: `%${search}%` } },
                    { email: { [Op.like]: `%${search}%` } }
                ];
            }

            const { rows: utilisateurs, count } = await Utilisateur.findAndCountAll({
                where: whereConditions,
                attributes: { exclude: ['mot_de_passe', 'token_reset'] },
                order: [[sort_by, sort_order]],
                limit: parseInt(limit),
                offset: parseInt(offset)
            });

            res.json({
                success: true,
                data: {
                    utilisateurs,
                    pagination: {
                        current_page: parseInt(page),
                        total_pages: Math.ceil(count / limit),
                        total_items: count,
                        items_per_page: parseInt(limit)
                    }
                }
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la récupération des utilisateurs',
                error: error.message
            });
        }
    }

    // Obtenir un utilisateur par ID
    async getUtilisateurById(req, res) {
        try {
            const { id } = req.params;
            
            const utilisateur = await Utilisateur.findByPk(id, {
                attributes: { exclude: ['mot_de_passe', 'token_reset'] }
            });

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

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

    // Créer un nouvel utilisateur
    async createUtilisateur(req, res) {
        const transaction = await sequelize.transaction();
        
        try {
            const {
                nom,
                prenom,
                email,
                mot_de_passe,
                telephone,
                role,
                date_embauche,
                salaire,
                adresse,
                date_naissance
            } = req.body;

            // Vérifier si l'email existe déjà
            const existingUser = await Utilisateur.findOne({
                where: { email }
            });

            if (existingUser) {
                await transaction.rollback();
                return res.status(400).json({
                    success: false,
                    message: 'Cet email est déjà utilisé'
                });
            }

            // Créer l'utilisateur
            const nouveauUtilisateur = await Utilisateur.create({
                nom,
                prenom,
                email,
                mot_de_passe,
                telephone,
                role: role || 'serveur',
                date_embauche: date_embauche ? new Date(date_embauche) : null,
                salaire: salaire ? parseFloat(salaire) : null,
                adresse,
                date_naissance: date_naissance ? new Date(date_naissance) : null,
                photo: req.file ? `/uploads/utilisateurs/${req.file.filename}` : null
            }, { transaction });

            await transaction.commit();

            res.status(201).json({
                success: true,
                message: 'Utilisateur créé avec succès',
                data: nouveauUtilisateur.toSafeJSON()
            });
        } catch (error) {
            await transaction.rollback();
            
            // Supprimer le fichier uploadé en cas d'erreur
            if (req.file) {
                try {
                    await fs.unlink(req.file.path);
                } catch (unlinkError) {
                    console.error('Erreur lors de la suppression du fichier:', unlinkError);
                }
            }

            res.status(500).json({
                success: false,
                message: 'Erreur lors de la création de l\'utilisateur',
                error: error.message
            });
        }
    }

    // Mettre à jour un utilisateur
    async updateUtilisateur(req, res) {
        const transaction = await sequelize.transaction();
        
        try {
            const { id } = req.params;
            const updateData = { ...req.body };

            // Retirer le mot de passe des données si il est vide
            if (updateData.mot_de_passe === '') {
                delete updateData.mot_de_passe;
            }

            // Vérifier si l'utilisateur existe
            const utilisateur = await Utilisateur.findByPk(id);
            if (!utilisateur) {
                await transaction.rollback();
                return res.status(404).json({
                    success: false,
                    message: 'Utilisateur non trouvé'
                });
            }

            // Vérifier l'unicité de l'email si modifié
            if (updateData.email && updateData.email !== utilisateur.email) {
                const existingUser = await Utilisateur.findOne({
                    where: { 
                        email: updateData.email,
                        id: { [Op.ne]: id }
                    }
                });

                if (existingUser) {
                    await transaction.rollback();
                    return res.status(400).json({
                        success: false,
                        message: 'Cet email est déjà utilisé par un autre utilisateur'
                    });
                }
            }

            // Ajouter la nouvelle photo si uploadée
            if (req.file) {
                // Supprimer l'ancienne photo
                if (utilisateur.photo) {
                    const oldPhotoPath = path.join(__dirname, '../uploads/utilisateurs', path.basename(utilisateur.photo));
                    try {
                        await fs.unlink(oldPhotoPath);
                    } catch (error) {
                        console.log('Ancienne photo non trouvée ou déjà supprimée');
                    }
                }
                updateData.photo = `/uploads/utilisateurs/${req.file.filename}`;
            }

            // Convertir les dates
            if (updateData.date_embauche) {
                updateData.date_embauche = new Date(updateData.date_embauche);
            }
            if (updateData.date_naissance) {
                updateData.date_naissance = new Date(updateData.date_naissance);
            }
            if (updateData.salaire) {
                updateData.salaire = parseFloat(updateData.salaire);
            }

            // Mettre à jour l'utilisateur
            await utilisateur.update(updateData, { transaction });

            await transaction.commit();

            // Recharger l'utilisateur avec les nouvelles données
            await utilisateur.reload();

            res.json({
                success: true,
                message: 'Utilisateur mis à jour avec succès',
                data: utilisateur.toSafeJSON()
            });
        } catch (error) {
            await transaction.rollback();
            
            // Supprimer le nouveau fichier en cas d'erreur
            if (req.file) {
                try {
                    await fs.unlink(req.file.path);
                } catch (unlinkError) {
                    console.error('Erreur lors de la suppression du fichier:', unlinkError);
                }
            }

            res.status(500).json({
                success: false,
                message: 'Erreur lors de la mise à jour de l\'utilisateur',
                error: error.message
            });
        }
    }

    // Supprimer un utilisateur
    async deleteUtilisateur(req, res) {
        const transaction = await sequelize.transaction();
        
        try {
            const { id } = req.params;

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

            // Supprimer la photo si elle existe
            if (utilisateur.photo) {
                const photoPath = path.join(__dirname, '../uploads/utilisateurs', path.basename(utilisateur.photo));
                try {
                    await fs.unlink(photoPath);
                } catch (error) {
                    console.log('Photo non trouvée ou déjà supprimée');
                }
            }

            await utilisateur.destroy({ transaction });
            await transaction.commit();

            res.json({
                success: true,
                message: 'Utilisateur supprimé avec succès'
            });
        } catch (error) {
            await transaction.rollback();
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la suppression de l\'utilisateur',
                error: error.message
            });
        }
    }

    // Changer le statut d'un utilisateur
    async changeStatut(req, res) {
        try {
            const { id } = req.params;
            const { statut } = req.body;

            if (!['actif', 'inactif', 'suspendu'].includes(statut)) {
                return res.status(400).json({
                    success: false,
                    message: 'Statut invalide'
                });
            }

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

            await utilisateur.update({ statut });

            res.json({
                success: true,
                message: `Statut changé vers "${statut}" avec succès`,
                data: utilisateur.toSafeJSON()
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors du changement de statut',
                error: error.message
            });
        }
    }

    // Réinitialiser le mot de passe
    async resetPassword(req, res) {
        try {
            const { id } = req.params;
            const { nouveau_mot_de_passe } = req.body;

            if (!nouveau_mot_de_passe || nouveau_mot_de_passe.length < 6) {
                return res.status(400).json({
                    success: false,
                    message: 'Le mot de passe doit contenir au moins 6 caractères'
                });
            }

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

            await utilisateur.update({ 
                mot_de_passe: nouveau_mot_de_passe,
                token_reset: null,
                token_reset_expire: null
            });

            res.json({
                success: true,
                message: 'Mot de passe réinitialisé avec succès'
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la réinitialisation du mot de passe',
                error: error.message
            });
        }
    }

    // Obtenir les statistiques des utilisateurs
    async getStats(req, res) {
        try {
            const stats = await sequelize.query(`
                SELECT 
                    COUNT(*) as total_utilisateurs,
                    COUNT(CASE WHEN statut = 'actif' THEN 1 END) as actifs,
                    COUNT(CASE WHEN statut = 'inactif' THEN 1 END) as inactifs,
                    COUNT(CASE WHEN statut = 'suspendu' THEN 1 END) as suspendus,
                    COUNT(CASE WHEN role = 'admin' THEN 1 END) as admins,
                    COUNT(CASE WHEN role = 'manager' THEN 1 END) as managers,
                    COUNT(CASE WHEN role = 'serveur' THEN 1 END) as serveurs,
                    COUNT(CASE WHEN role = 'cuisinier' THEN 1 END) as cuisiniers,
                    COUNT(CASE WHEN role = 'caissier' THEN 1 END) as caissiers,
                    COUNT(CASE WHEN derniere_connexion >= DATE_SUB(NOW(), INTERVAL 7 DAY) THEN 1 END) as connectes_7_jours,
                    COUNT(CASE WHEN derniere_connexion >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN 1 END) as connectes_30_jours
                FROM utilisateurs 
                WHERE est_actif = 1
            `, {
                type: sequelize.QueryTypes.SELECT
            });

            const recentUsers = await Utilisateur.findAll({
                attributes: ['id', 'nom', 'prenom', 'role', 'cree_le'],
                order: [['cree_le', 'DESC']],
                limit: 5
            });

            res.json({
                success: true,
                data: {
                    stats: stats[0],
                    recent_users: recentUsers
                }
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la récupération des statistiques',
                error: error.message
            });
        }
    }

    // Rechercher des utilisateurs
    async searchUtilisateurs(req, res) {
        try {
            const { q, role, limit = 10 } = req.query;

            if (!q || q.length < 2) {
                return res.status(400).json({
                    success: false,
                    message: 'La recherche doit contenir au moins 2 caractères'
                });
            }

            const whereConditions = {
                [Op.and]: [
                    { est_actif: true },
                    {
                        [Op.or]: [
                            { nom: { [Op.like]: `%${q}%` } },
                            { prenom: { [Op.like]: `%${q}%` } },
                            { email: { [Op.like]: `%${q}%` } }
                        ]
                    }
                ]
            };

            if (role) {
                whereConditions[Op.and].push({ role });
            }

            const utilisateurs = await Utilisateur.findAll({
                where: whereConditions,
                attributes: ['id', 'nom', 'prenom', 'email', 'role', 'photo'],
                order: [['nom', 'ASC'], ['prenom', 'ASC']],
                limit: parseInt(limit)
            });

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

    // Login utilisateur
    async login(req, res) {
        try {
            const { email, mot_de_passe } = req.body;

            if (!email || !mot_de_passe) {
                return res.status(400).json({
                    success: false,
                    message: 'Email et mot de passe requis'
                });
            }

            // Trouver l'utilisateur par email
            const utilisateur = await Utilisateur.findOne({
                where: { 
                    email,
                    est_actif: true,
                    statut: 'actif'
                }
            });

            if (!utilisateur) {
                return res.status(401).json({
                    success: false,
                    message: 'Email ou mot de passe incorrect'
                });
            }

            // Vérifier le mot de passe
            const isValid = await utilisateur.verifierMotDePasse(mot_de_passe);
            if (!isValid) {
                return res.status(401).json({
                    success: false,
                    message: 'Email ou mot de passe incorrect'
                });
            }

            // Mettre à jour la dernière connexion
            await utilisateur.update({ 
                derniere_connexion: new Date() 
            });

            // Générer le token JWT
            const token = jwt.sign(
                { 
                    userId: utilisateur.id,
                    email: utilisateur.email,
                    role: utilisateur.role
                },
                process.env.JWT_SECRET || 'secret_key',
                { expiresIn: '24h' }
            );

            res.json({
                success: true,
                message: 'Connexion réussie',
                data: {
                    token,
                    utilisateur: utilisateur.toSafeJSON()
                }
            });
        } catch (error) {
            res.status(500).json({
                success: false,
                message: 'Erreur lors de la connexion',
                error: error.message
            });
        }
    }
}

module.exports = {
    UtilisateurController: new UtilisateurController(),
    uploadPhoto: upload.single('photo')
};
