const express = require('express');
const multer = require('multer');
const cors = require('cors');
const path = require('path');
const fs = require('fs');
const sqlite3 = require('sqlite3').verbose();
const AdmZip = require('adm-zip');


const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(cors());
app.use(express.json());

// Arborescence demandée
const uploadDir = path.join(__dirname, 'uploads');
const imagesDir = path.join(uploadDir, 'images');
const dataDir = path.join(uploadDir, 'data');
const exportsDir = path.join(__dirname, 'exports');

// S'assurer que les dossiers existent
[uploadDir, imagesDir, dataDir, exportsDir].forEach(dir => {
    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
    }
});

// Initialisation de la base de données SQLite
const dbPath = path.join(dataDir, 'database.sqlite');
const db = new sqlite3.Database(dbPath, (err) => {
    if (err) {
        console.error('Erreur de connexion à SQLite:', err.message);
    } else {
        console.log('Connecté à la base de données SQLite.');
        db.run(`CREATE TABLE IF NOT EXISTS user_stats (
            wallet_hash TEXT PRIMARY KEY,
            photo_count INTEGER DEFAULT 0,
            last_upload DATETIME DEFAULT CURRENT_TIMESTAMP
        )`);
    }
});

// Configuration de multer pour le stockage des fichiers
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, imagesDir); // Les photos vont dans uploads/images/
    },
    filename: function (req, file, cb) {
        // Créer un nom de fichier unique tout en gardant l'extension originale
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
        const ext = path.extname(file.originalname);
        cb(null, file.fieldname + '-' + uniqueSuffix + ext);
    }
});

const upload = multer({ 
    storage: storage,
    limits: {
        fileSize: 15 * 1024 * 1024 // Limite de taille: 15 MB
    },
    fileFilter: (req, file, cb) => {
        const ext = path.extname(file.originalname).toLowerCase();
        const allowedExts = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
        
        // Accepter si c'est un mimetype image OU si l'extension est celle d'une image
        if (file.mimetype.startsWith('image/') || allowedExts.includes(ext) || file.mimetype === 'application/octet-stream') {
            cb(null, true);
        } else {
            console.error(`Fichier rejeté: mimetype=${file.mimetype}, extension=${ext}`);
            cb(new Error('Seules les images sont autorisées !'), false);
        }
    }
});

// Routes de base
app.get('/api/health', (req, res) => {
    res.json({ status: 'ok', message: 'Le serveur backend IA fonctionne' });
});

// Route pour l'upload de photo + données JSON
// Attend un form-data avec un champ nommé 'photo' et un champ texte 'plotting'
app.post('/api/upload', upload.single('photo'), (req, res) => {
    try {
        if (!req.file) {
            return res.status(400).json({ error: 'Aucune photo fournie' });
        }
        
        let plottingData = {};
        if (req.body.plotting) {
            try {
                plottingData = JSON.parse(req.body.plotting);
            } catch (e) {
                console.error("Erreur parsing JSON:", e);
                return res.status(400).json({ error: 'Le champ plotting doit être un JSON valide' });
            }
        }

        // Nom de base sans l'extension
        const baseFilename = path.parse(req.file.filename).name;
        const jsonFilename = `${baseFilename}.json`;
        const jsonFilePath = path.join(dataDir, jsonFilename);

        // Sauvegarde du JSON dans uploads/data/
        fs.writeFileSync(jsonFilePath, JSON.stringify(plottingData, null, 2));

        // Mise à jour de la BDD si on a un wallet_hash
        const walletHash = plottingData.wallet_hash;
        if (walletHash) {
            db.run(`
                INSERT INTO user_stats (wallet_hash, photo_count, last_upload) 
                VALUES (?, 1, CURRENT_TIMESTAMP)
                ON CONFLICT(wallet_hash) DO UPDATE SET 
                photo_count = photo_count + 1,
                last_upload = CURRENT_TIMESTAMP
            `, [walletHash], function(err) {
                if (err) {
                    console.error("Erreur lors de la mise à jour des stats :", err);
                } else {
                    console.log(`Stats mises à jour pour le wallet_hash ${walletHash.substring(0, 8)}...`);
                }
            });
        }
        
        console.log(`Données reçues et sauvegardées:`);
        console.log(`- Image: uploads/images/${req.file.filename}`);
        console.log(`- JSON : uploads/data/${jsonFilename}`);
        
        res.status(200).json({
            message: 'Photo et données uploadées avec succès',
            file: {
                filename: req.file.filename,
                url: `/uploads/images/${req.file.filename}`,
                size: req.file.size
            },
            data: {
                filename: jsonFilename
            }
        });
    } catch (error) {
        console.error('Erreur lors de l\'upload:', error);
        res.status(500).json({ error: 'Erreur interne du serveur lors de l\'upload' });
    }
});

// Route pour récupérer toutes les photos disponibles
app.get('/api/photos', (req, res) => {
    try {
        fs.readdir(imagesDir, (err, files) => {
            if (err) {
                return res.status(500).json({ error: 'Impossible de lire le dossier des photos' });
            }
            
            const photos = files.map(file => ({
                filename: file,
                url: `/uploads/images/${file}`
            }));
            
            res.status(200).json({ photos });
        });
    } catch (error) {
        res.status(500).json({ error: 'Erreur serveur' });
    }
});

// Route pour récupérer les statistiques d'un wallet_hash
app.get('/api/stats/:wallet_hash', (req, res) => {
    const walletHash = req.params.wallet_hash;
    
    db.get('SELECT photo_count, last_upload FROM user_stats WHERE wallet_hash = ?', [walletHash], (err, row) => {
        if (err) {
            return res.status(500).json({ error: 'Erreur lors de la lecture des statistiques' });
        }
        
        if (row) {
            res.json({ status: 'ok', stats: row });
        } else {
            res.json({ status: 'ok', stats: { photo_count: 0, last_upload: null } });
        }
    });
});

// Route pour récupérer TOUS les contributeurs
app.get('/api/contributors', (req, res) => {
    db.all('SELECT * FROM user_stats ORDER BY photo_count DESC', [], (err, rows) => {
        if (err) {
            return res.status(500).json({ error: 'Erreur lors de la lecture des contributeurs' });
        }
        res.json({ contributors: rows });
    });
});

// Route pour récupérer toutes les données (Photos + JSON)
app.get('/api/all-data', (req, res) => {
    try {
        fs.readdir(imagesDir, (err, files) => {
            if (err) {
                return res.status(500).json({ error: 'Impossible de lire le dossier des photos' });
            }
            
            const allData = files.map(file => {
                const baseName = path.parse(file).name;
                const jsonPath = path.join(dataDir, `${baseName}.json`);
                let plotting = null;
                
                if (fs.existsSync(jsonPath)) {
                    try {
                        plotting = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
                    } catch (e) {
                        console.error(`Erreur lecture JSON pour ${file}`);
                    }
                }
                
                return {
                    filename: file,
                    imageUrl: `/uploads/images/${file}`,
                    data: plotting
                };
            });
            
            res.status(200).json({ data: allData });
        });
    } catch (error) {
        res.status(500).json({ error: 'Erreur serveur' });
    }
});

// Route pour mettre à jour les données JSON d'une session
app.put('/api/data/:filename', (req, res) => {
    const filename = req.params.filename;
    const baseName = path.parse(filename).name;
    const jsonPath = path.join(dataDir, `${baseName}.json`);

    try {
        if (!fs.existsSync(jsonPath)) {
            return res.status(404).json({ error: 'Fichier JSON non trouvé' });
        }

        // On écrase le fichier avec les nouvelles données reçues
        const newData = req.body;
        fs.writeFileSync(jsonPath, JSON.stringify(newData, null, 2));

        console.log(`Données mises à jour pour : ${baseName}.json`);
        res.status(200).json({ message: 'Données mises à jour avec succès' });
    } catch (error) {
        console.error('Erreur lors de la mise à jour du JSON:', error);
        res.status(500).json({ error: 'Erreur serveur lors de la mise à jour' });
    }
});

// Route pour exporter toutes les données en ZIP
app.get('/api/export/zip', (req, res) => {
    try {
        const zip = new AdmZip();
        
        // Ajouter les dossiers au ZIP
        if (fs.existsSync(imagesDir)) zip.addLocalFolder(imagesDir, 'images');
        if (fs.existsSync(dataDir)) zip.addLocalFolder(dataDir, 'data');
        
        const zipFilename = `dataset_export_${Date.now()}.zip`;
        const zipPath = path.join(exportsDir, zipFilename);
        
        // Sauvegarder sur le disque
        zip.writeZip(zipPath);
        
        // Envoyer le fichier au client
        res.download(zipPath, zipFilename, (err) => {
            if (err) console.error("Erreur lors de l'envoi du ZIP:", err);
            // Optionnel: supprimer le ZIP local après envoi si vous voulez gagner de la place
            // fs.unlinkSync(zipPath);
        });
    } catch (error) {
        console.error('Erreur lors de la création du ZIP:', error);
        res.status(500).json({ error: 'Erreur lors de la création de l\'archive' });
    }
});

// Route pour archiver et vider les dossiers uploads
app.post('/api/export/archive', (req, res) => {
    try {
        const archiveName = `archive_${new Date().toISOString().replace(/[:.]/g, '-')}`;
        const archivePath = path.join(exportsDir, archiveName);
        
        if (!fs.existsSync(archivePath)) {
            fs.mkdirSync(archivePath, { recursive: true });
        }

        // Fonction pour déplacer les fichiers
        const moveFiles = (source, destSubDir) => {
            const dest = path.join(archivePath, destSubDir);
            if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
            
            const files = fs.readdirSync(source);
            files.forEach(file => {
                // Ne pas déplacer la base de données sqlite
                if (file === 'database.sqlite') return;
                
                const oldPath = path.join(source, file);
                const newPath = path.join(dest, file);
                
                try {
                    fs.renameSync(oldPath, newPath);
                } catch (e) {
                    // Fallback si renameSync échoue (ex: disque différent)
                    fs.copyFileSync(oldPath, newPath);
                    fs.unlinkSync(oldPath);
                }
            });
        };

        moveFiles(imagesDir, 'images');
        moveFiles(dataDir, 'data');

        res.json({ message: 'Données archivées avec succès', archive: archiveName });
    } catch (error) {
        console.error('Erreur lors de l\'archivage:', error);
        res.status(500).json({ error: 'Erreur lors de l\'archivage des données' });
    }
});

// Servir les fichiers statiques (pour pouvoir accéder aux photos via URL)
app.use('/uploads/images', express.static(imagesDir));

// Gestion des erreurs
app.use((err, req, res, next) => {
    if (err instanceof multer.MulterError) {
        if (err.code === 'LIMIT_FILE_SIZE') {
            return res.status(400).json({ error: 'Le fichier est trop volumineux (limite 15MB)' });
        }
    }
    console.error(err.stack);
    res.status(500).json({ error: err.message || 'Une erreur inattendue est survenue' });
});

// Démarrer le serveur
app.listen(PORT, () => {
    console.log(`=================================`);
    console.log(`Serveur Backend IA démarré`);
    console.log(`Port: ${PORT}`);
    console.log(`Dossiers:`);
    console.log(` - Images: ${imagesDir}`);
    console.log(` - Data  : ${dataDir}`);
    console.log(` - Export: ${exportsDir}`);
    console.log(`=================================`);
});
