const dbManager = require('../database/DatabaseManager');

class GroupRepository {
    
    // Erstelle neue Gruppe mit Bildern (Transaction)
    async createGroup(groupData) {
        return await dbManager.transaction(async (db) => {
            // Füge Gruppe hinzu
            const groupResult = await db.run(`
                INSERT INTO groups (group_id, year, title, description, name, upload_date, approved)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            `, [
                groupData.groupId,
                groupData.year,
                groupData.title,
                groupData.description || null,
                groupData.name || null,
                groupData.uploadDate,
                groupData.approved || false
            ]);

            // Füge Bilder hinzu
            if (groupData.images && groupData.images.length > 0) {
                for (const image of groupData.images) {
                    await db.run(`
                        INSERT INTO images (group_id, file_name, original_name, file_path, upload_order, file_size, mime_type, preview_path, image_description)
                        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                    `, [
                        groupData.groupId,
                        image.fileName,
                        image.originalName,
                        image.filePath,
                        image.uploadOrder,
                        image.fileSize || null,
                        image.mimeType || null,
                        image.previewPath || null,
                        image.imageDescription || null
                    ]);
                }
            }

            return groupResult.id;
        });
    }

    // Hole Gruppe mit Bildern nach Group-ID
    async getGroupById(groupId) {
        const group = await dbManager.get(`
            SELECT * FROM groups WHERE group_id = ?
        `, [groupId]);

        if (!group) {
            return null;
        }

        const images = await dbManager.all(`
            SELECT * FROM images 
            WHERE group_id = ? 
            ORDER BY upload_order ASC
        `, [groupId]);

        return {
            groupId: group.group_id,
            year: group.year,
            title: group.title,
            description: group.description,
            name: group.name,
            uploadDate: group.upload_date,
            images: images.map(img => ({
                id: img.id,
                fileName: img.file_name,
                originalName: img.original_name,
                filePath: img.file_path,
                previewPath: img.preview_path,
                uploadOrder: img.upload_order,
                fileSize: img.file_size,
                mimeType: img.mime_type,
                imageDescription: img.image_description
            })),
            imageCount: images.length
        };
    }

    // Hole alle Gruppen (mit Paginierung)
    async getAllGroups(limit = null, offset = 0) {
        let sql = `
            SELECT g.*, COUNT(i.id) as image_count
            FROM groups g
            LEFT JOIN images i ON g.group_id = i.group_id
            GROUP BY g.group_id
            ORDER BY g.upload_date DESC
        `;
        
        const params = [];
        if (limit) {
            sql += ` LIMIT ? OFFSET ?`;
            params.push(limit, offset);
        }

        const groups = await dbManager.all(sql, params);
        
        return {
            groups: groups.map(group => ({
                groupId: group.group_id,
                year: group.year,
                title: group.title,
                description: group.description,
                name: group.name,
                uploadDate: group.upload_date,
                imageCount: group.image_count
            })),
            total: groups.length
        };
    }

    // Hole alle Gruppen mit Bildern für Slideshow (nur freigegebene)
    async getAllGroupsWithImages() {
        const groupFormatter = require('../utils/groupFormatter');

        const groups = await dbManager.all(`
            SELECT * FROM groups 
            WHERE approved = TRUE 
            ORDER BY upload_date DESC
        `);

        const result = [];
        for (const group of groups) {
            const images = await dbManager.all(`
                SELECT * FROM images 
                WHERE group_id = ? 
                ORDER BY upload_order ASC
            `, [group.group_id]);

            result.push(groupFormatter.formatGroupDetail(group, images));
        }

        return result;
    }

    // Lösche Gruppe und alle Bilder
    async deleteGroup(groupId) {
        return await dbManager.transaction(async (db) => {
            // Erst alle Bilddateien physisch löschen
            const images = await db.all(`
                SELECT * FROM images WHERE group_id = ?
            `, [groupId]);

            const fs = require('fs').promises;
            const path = require('path');
            
            for (const image of images) {
                try {
                    const absolutePath = path.join(__dirname, '..', image.file_path);
                    await fs.unlink(absolutePath);
                    console.log(`✓ Bilddatei gelöscht: ${absolutePath}`);
                } catch (error) {
                    console.warn(`⚠️ Konnte Bilddatei nicht löschen: ${image.file_path}`, error.message);
                }
            }

            // Dann Gruppe aus Datenbank löschen (Bilder werden durch CASCADE gelöscht)
            const result = await db.run(`
                DELETE FROM groups WHERE group_id = ?
            `, [groupId]);

            console.log(`✓ Gruppe gelöscht: ${groupId} (${images.length} Bilder)`);
            return result.changes > 0;
        });
    }

    // Update Gruppe
    async updateGroup(groupId, updates) {
        const setClause = [];
        const params = [];

        if (updates.year !== undefined) {
            setClause.push('year = ?');
            params.push(updates.year);
        }
        if (updates.title !== undefined) {
            setClause.push('title = ?');
            params.push(updates.title);
        }
        if (updates.description !== undefined) {
            setClause.push('description = ?');
            params.push(updates.description);
        }
        if (updates.name !== undefined) {
            setClause.push('name = ?');
            params.push(updates.name);
        }

        if (setClause.length === 0) {
            return false;
        }

        params.push(groupId);
        
        const result = await dbManager.run(`
            UPDATE groups SET ${setClause.join(', ')} WHERE group_id = ?
        `, params);

        return result.changes > 0;
    }

    // Gruppe Freigabe-Status aktualisieren
    async updateGroupApproval(groupId, approved) {
        const result = await dbManager.run(`
            UPDATE groups SET approved = ? WHERE group_id = ?
        `, [approved, groupId]);

        return result.changes > 0;
    }

    // Einzelnes Bild löschen
    async deleteImage(groupId, imageId) {
        return await dbManager.transaction(async (db) => {
            // Prüfe ob Bild existiert
            const image = await db.get(`
                SELECT * FROM images WHERE id = ? AND group_id = ?
            `, [imageId, groupId]);

            if (!image) {
                return false;
            }

            // Lösche Datei vom Dateisystem
            const fs = require('fs').promises;
            const path = require('path');
            try {
                // Konvertiere relativen Pfad zu absolutem Pfad im Container
                // image.file_path ist "/upload/dateiname.ext", wir brauchen "/usr/src/app/src/upload/dateiname.ext"
                const absolutePath = path.join(__dirname, '..', image.file_path);
                await fs.unlink(absolutePath);
                console.log(`✓ Bilddatei gelöscht: ${absolutePath}`);
            } catch (error) {
                console.warn(`⚠️ Konnte Bilddatei nicht löschen: ${image.file_path}`, error.message);
                // Datei-Löschfehler sollen nicht das Löschen aus der Datenbank verhindern
            }

            // Lösche aus Datenbank
            const result = await db.run(`
                DELETE FROM images WHERE id = ? AND group_id = ?
            `, [imageId, groupId]);

            // Aktualisiere upload_order der verbleibenden Bilder
            await db.run(`
                UPDATE images 
                SET upload_order = upload_order - 1 
                WHERE group_id = ? AND upload_order > ?
            `, [groupId, image.upload_order]);

            return result.changes > 0;
        });
    }

    // Alle Gruppen für Moderation (mit Freigabestatus und Bildanzahl)
    async getAllGroupsWithModerationInfo() {
        const groupFormatter = require('../utils/groupFormatter');

        const groups = await dbManager.all(`
            SELECT * FROM groups 
            ORDER BY approved ASC, upload_date DESC
        `);

        const result = [];
        for (const group of groups) {
            const images = await dbManager.all(`
                SELECT * FROM images 
                WHERE group_id = ? 
                ORDER BY upload_order ASC
            `, [group.group_id]);

            result.push(groupFormatter.formatGroupDetail(group, images));
        }

        return result;
    }

    // Hole Gruppe für Moderation (inkl. nicht-freigegebene)
    async getGroupForModeration(groupId) {
        const group = await dbManager.get(`
            SELECT * FROM groups WHERE group_id = ?
        `, [groupId]);

        if (!group) {
            return null;
        }

        const images = await dbManager.all(`
            SELECT * FROM images 
            WHERE group_id = ? 
            ORDER BY upload_order ASC
        `, [groupId]);

        const groupFormatter = require('../utils/groupFormatter');
        return groupFormatter.formatGroupDetail(group, images);
    }

    // Statistiken (erweitert um Freigabe-Status)
    async getStats() {
        const groupCount = await dbManager.get('SELECT COUNT(*) as count FROM groups');
        const imageCount = await dbManager.get('SELECT COUNT(*) as count FROM images');
        const approvedGroups = await dbManager.get('SELECT COUNT(*) as count FROM groups WHERE approved = TRUE');
        const pendingGroups = await dbManager.get('SELECT COUNT(*) as count FROM groups WHERE approved = FALSE');
        const latestGroup = await dbManager.get(`
            SELECT upload_date FROM groups ORDER BY upload_date DESC LIMIT 1
        `);

        return {
            totalGroups: groupCount.count,
            totalImages: imageCount.count,
            approvedGroups: approvedGroups.count,
            pendingGroups: pendingGroups.count,
            latestUpload: latestGroup ? latestGroup.upload_date : null
        };
    }

    // Aktualisiere die Reihenfolge der Bilder in einer Gruppe
    async updateImageOrder(groupId, imageIds) {
        if (!groupId) {
            throw new Error('Group ID is required');
        }
        
        if (!Array.isArray(imageIds) || imageIds.length === 0) {
            throw new Error('Image IDs array is required and cannot be empty');
        }

        return await dbManager.transaction(async (db) => {
            // Zunächst prüfen, ob die Gruppe existiert
            const group = await db.get('SELECT group_id FROM groups WHERE group_id = ?', [groupId]);
            if (!group) {
                throw new Error(`Group with ID ${groupId} not found`);
            }

            // Alle Bilder der Gruppe laden und prüfen ob alle IDs gültig sind
            const existingImages = await db.all(
                'SELECT id, file_name FROM images WHERE group_id = ? ORDER BY upload_order ASC', 
                [groupId]
            );
            
            const existingImageIds = existingImages.map(img => img.id);
            
            // Prüfen ob alle übergebenen IDs zur Gruppe gehören
            const invalidIds = imageIds.filter(id => !existingImageIds.includes(id));
            if (invalidIds.length > 0) {
                throw new Error(`Invalid image IDs found: ${invalidIds.join(', ')}. These images do not belong to group ${groupId}`);
            }
            
            // Prüfen ob alle Bilder der Gruppe in der Liste enthalten sind
            const missingIds = existingImageIds.filter(id => !imageIds.includes(id));
            if (missingIds.length > 0) {
                throw new Error(`Missing image IDs: ${missingIds.join(', ')}. All images of the group must be included in the reorder operation`);
            }

            // Batch-Update der upload_order Werte
            let updateCount = 0;
            for (let i = 0; i < imageIds.length; i++) {
                const imageId = imageIds[i];
                const newOrder = i + 1; // upload_order beginnt bei 1
                
                const result = await db.run(
                    'UPDATE images SET upload_order = ? WHERE id = ? AND group_id = ?',
                    [newOrder, imageId, groupId]
                );
                
                if (result.changes === 0) {
                    throw new Error(`Failed to update image with ID ${imageId}`);
                }
                
                updateCount += result.changes;
            }
            
            return {
                groupId: groupId,
                updatedImages: updateCount,
                newOrder: imageIds
            };
        });
    }

    // Aktualisiere die Beschreibung eines einzelnen Bildes
    async updateImageDescription(imageId, groupId, description) {
        // Validierung: Max 200 Zeichen
        if (description && description.length > 200) {
            throw new Error('Image description must not exceed 200 characters');
        }

        const result = await dbManager.run(`
            UPDATE images 
            SET image_description = ? 
            WHERE id = ? AND group_id = ?
        `, [description || null, imageId, groupId]);

        return result.changes > 0;
    }

    // Batch-Update für mehrere Bildbeschreibungen
    async updateBatchImageDescriptions(groupId, descriptions) {
        if (!Array.isArray(descriptions) || descriptions.length === 0) {
            throw new Error('Descriptions array is required and cannot be empty');
        }

        return await dbManager.transaction(async (db) => {
            let updateCount = 0;

            for (const desc of descriptions) {
                const { imageId, description } = desc;

                // Validierung: Max 200 Zeichen
                if (description && description.length > 200) {
                    throw new Error(`Image description for image ${imageId} must not exceed 200 characters`);
                }

                // Prüfe ob Bild zur Gruppe gehört
                const image = await db.get(`
                    SELECT id FROM images WHERE id = ? AND group_id = ?
                `, [imageId, groupId]);

                if (!image) {
                    throw new Error(`Image with ID ${imageId} not found in group ${groupId}`);
                }

                // Update Beschreibung
                const result = await db.run(`
                    UPDATE images 
                    SET image_description = ? 
                    WHERE id = ? AND group_id = ?
                `, [description || null, imageId, groupId]);

                updateCount += result.changes;
            }

            return {
                groupId: groupId,
                updatedImages: updateCount
            };
        });
    }

    // Findet Gruppen, die zum Löschen anstehen (approved=false & älter als N Tage)
    async findUnapprovedGroupsOlderThan(days) {
        const cutoffDate = new Date();
        cutoffDate.setDate(cutoffDate.getDate() - days);
        const cutoffDateStr = cutoffDate.toISOString();

        const groups = await dbManager.all(`
            SELECT * FROM groups
            WHERE approved = FALSE 
            AND upload_date < ?
            ORDER BY upload_date ASC
        `, [cutoffDateStr]);

        return groups;
    }

    // Hole Statistiken für Gruppe (für Deletion Log)
    async getGroupStatistics(groupId) {
        const group = await dbManager.get(`
            SELECT * FROM groups WHERE group_id = ?
        `, [groupId]);

        if (!group) {
            return null;
        }

        const images = await dbManager.all(`
            SELECT file_size, file_path, preview_path FROM images 
            WHERE group_id = ?
        `, [groupId]);

        const totalFileSize = images.reduce((sum, img) => sum + (img.file_size || 0), 0);

        return {
            groupId: group.group_id,
            year: group.year,
            imageCount: images.length,
            uploadDate: group.upload_date,
            totalFileSize: totalFileSize,
            images: images
        };
    }

    // Löscht Gruppe komplett (inkl. DB-Einträge und Dateien)
    async deleteGroupCompletely(groupId) {
        return await dbManager.transaction(async (db) => {
            // Hole alle Bilder der Gruppe (für Datei-Löschung)
            const images = await db.all(`
                SELECT file_path, preview_path FROM images 
                WHERE group_id = ?
            `, [groupId]);

            // Lösche Gruppe (CASCADE löscht automatisch Bilder aus DB)
            const result = await db.run(`
                DELETE FROM groups WHERE group_id = ?
            `, [groupId]);

            if (result.changes === 0) {
                throw new Error(`Group with ID ${groupId} not found`);
            }

            return {
                deletedImages: images.length,
                imagePaths: images
            };
        });
    }
}

module.exports = new GroupRepository();