const sqlite3 = require('sqlite3').verbose();
const path = require('path');
const fs = require('fs');

class DatabaseManager {
    constructor() {
        this.db = null;
        this.dbPath = null;
        this.schemaPath = path.join(__dirname, 'schema.sql');
    }

    getDatabasePath() {
        if (process.env.NODE_ENV === 'test') {
            return ':memory:';
        }
        return path.join(__dirname, '../data/db/image_uploader.db');
    }

    async initialize() {
        try {
            if (!this.dbPath) {
                this.dbPath = this.getDatabasePath();
            }
            // Stelle sicher, dass das data-Verzeichnis existiert (skip for in-memory)
            if (this.dbPath !== ':memory:') {
                const dataDir = path.dirname(this.dbPath);
                if (!fs.existsSync(dataDir)) {
                    fs.mkdirSync(dataDir, { recursive: true });
                }
            }

            // Öffne Datenbankverbindung (promisify for async/await)
            await new Promise((resolve, reject) => {
                this.db = new sqlite3.Database(this.dbPath, (err) => {
                    if (err) {
                        console.error('Fehler beim Öffnen der Datenbank:', err.message);
                        reject(err);
                    } else {
                        console.log('✓ SQLite Datenbank verbunden:', this.dbPath);
                        resolve();
                    }
                });
            });

            // Aktiviere Foreign Keys
            await this.run('PRAGMA foreign_keys = ON');
            
            // Erstelle Schema
            await this.createSchema();
            
            // Run database migrations (automatic on startup)
            await this.runMigrations();
            
            const skipPreviewGeneration = ['1', 'true', 'yes'].includes(String(process.env.SKIP_PREVIEW_GENERATION || '').toLowerCase());

            // Generate missing previews for existing images (skip in test mode or when explicitly disabled)
            if (process.env.NODE_ENV !== 'test' && !skipPreviewGeneration) {
                await this.generateMissingPreviews();
            }
            
            console.log('✓ Datenbank erfolgreich initialisiert');
        } catch (error) {
            console.error('Fehler bei Datenbank-Initialisierung:', error);
            throw error;
        }
    }

    async createSchema() {
        try {
            console.log('🔨 Erstelle Datenbank-Schema...');
            
            // Erstelle Groups Tabelle
            await this.run(`
                CREATE TABLE IF NOT EXISTS groups (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    group_id TEXT UNIQUE NOT NULL,
                    year INTEGER NOT NULL,
                    title TEXT NOT NULL,
                    description TEXT,
                    name TEXT,
                    upload_date DATETIME NOT NULL,
                    approved BOOLEAN DEFAULT FALSE,
                    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
                )
            `);
            
            // Migration: Füge approved Feld zu bestehenden Tabellen hinzu (falls nicht vorhanden)
            try {
                await this.run('ALTER TABLE groups ADD COLUMN approved BOOLEAN DEFAULT FALSE');
                console.log('✓ Approved Feld zur bestehenden Tabelle hinzugefügt');
            } catch (error) {
                // Feld existiert bereits - das ist okay
                if (!error.message.includes('duplicate column')) {
                    console.warn('Migration Warnung:', error.message);
                }
            }
            console.log('✓ Groups Tabelle erstellt');

            // Erstelle Images Tabelle
            await this.run(`
                CREATE TABLE IF NOT EXISTS images (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    group_id TEXT NOT NULL,
                    file_name TEXT NOT NULL,
                    original_name TEXT NOT NULL,
                    file_path TEXT NOT NULL,
                    upload_order INTEGER NOT NULL,
                    file_size INTEGER,
                    mime_type TEXT,
                    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                    FOREIGN KEY (group_id) REFERENCES groups(group_id) ON DELETE CASCADE
                )
            `);
            console.log('✓ Images Tabelle erstellt');

            // Migration: Füge preview_path Feld zur images Tabelle hinzu (falls nicht vorhanden)
            try {
                await this.run('ALTER TABLE images ADD COLUMN preview_path TEXT');
                console.log('✓ preview_path Feld zur images Tabelle hinzugefügt');
            } catch (error) {
                // Feld existiert bereits - das ist okay
                if (!error.message.includes('duplicate column')) {
                    console.warn('Migration Warnung:', error.message);
                }
            }

            // Migration: Füge image_description Feld zur images Tabelle hinzu (falls nicht vorhanden)
            try {
                await this.run('ALTER TABLE images ADD COLUMN image_description TEXT');
                console.log('✓ image_description Feld zur images Tabelle hinzugefügt');
            } catch (error) {
                // Feld existiert bereits - das ist okay
                if (!error.message.includes('duplicate column')) {
                    console.warn('Migration Warnung:', error.message);
                }
            }

            // Erstelle Deletion Log Tabelle
            await this.run(`
                CREATE TABLE IF NOT EXISTS deletion_log (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    group_id TEXT NOT NULL,
                    year INTEGER NOT NULL,
                    image_count INTEGER NOT NULL,
                    upload_date DATETIME NOT NULL,
                    deleted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                    deletion_reason TEXT DEFAULT 'auto_cleanup_7days',
                    total_file_size INTEGER
                )
            `);
            console.log('✓ Deletion Log Tabelle erstellt');

            // Erstelle Indizes
            await this.run('CREATE INDEX IF NOT EXISTS idx_groups_group_id ON groups(group_id)');
            await this.run('CREATE INDEX IF NOT EXISTS idx_groups_year ON groups(year)');
            await this.run('CREATE INDEX IF NOT EXISTS idx_groups_upload_date ON groups(upload_date)');
            await this.run('CREATE INDEX IF NOT EXISTS idx_groups_approved ON groups(approved)');
            await this.run('CREATE INDEX IF NOT EXISTS idx_groups_cleanup ON groups(approved, upload_date)');
            await this.run('CREATE INDEX IF NOT EXISTS idx_images_group_id ON images(group_id)');
            await this.run('CREATE INDEX IF NOT EXISTS idx_images_upload_order ON images(upload_order)');
            await this.run('CREATE INDEX IF NOT EXISTS idx_deletion_log_deleted_at ON deletion_log(deleted_at DESC)');
            await this.run('CREATE INDEX IF NOT EXISTS idx_deletion_log_year ON deletion_log(year)');
            console.log('✓ Indizes erstellt');

            // Erstelle Trigger
            await this.run(`
                CREATE TRIGGER IF NOT EXISTS update_groups_timestamp 
                AFTER UPDATE ON groups
                FOR EACH ROW
                BEGIN
                    UPDATE groups SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
                END
            `);
            console.log('✓ Trigger erstellt');

            // Admin Users Tabelle (für Session-Authentication)
            await this.run(`
                CREATE TABLE IF NOT EXISTS admin_users (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    username TEXT UNIQUE NOT NULL,
                    password_hash TEXT NOT NULL,
                    role TEXT NOT NULL DEFAULT 'admin',
                    is_active BOOLEAN NOT NULL DEFAULT 1,
                    requires_password_change BOOLEAN NOT NULL DEFAULT 0,
                    last_login_at DATETIME,
                    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
                )
            `);
            await this.run('CREATE UNIQUE INDEX IF NOT EXISTS idx_admin_users_username ON admin_users(username)');
            await this.run(`
                CREATE TRIGGER IF NOT EXISTS update_admin_users_timestamp
                AFTER UPDATE ON admin_users
                FOR EACH ROW
                BEGIN
                    UPDATE admin_users SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
                END
            `);
            console.log('✓ Admin Users Tabelle erstellt');
            
            console.log('✅ Datenbank-Schema vollständig erstellt');
        } catch (error) {
            console.error('💥 Fehler beim Erstellen des Schemas:', error);
            throw error;
        }
    }

    // Promise-wrapper für sqlite3.run
    run(sql, params = []) {
        return new Promise((resolve, reject) => {
            this.db.run(sql, params, function(err) {
                if (err) {
                    reject(err);
                } else {
                    resolve({ id: this.lastID, changes: this.changes });
                }
            });
        });
    }

    // Execute multi-statement SQL scripts (z. B. Migrationen mit Triggern)
    exec(sql) {
        return new Promise((resolve, reject) => {
            this.db.exec(sql, (err) => {
                if (err) {
                    reject(err);
                } else {
                    resolve();
                }
            });
        });
    }

    // Promise-wrapper für sqlite3.get
    get(sql, params = []) {
        return new Promise((resolve, reject) => {
            this.db.get(sql, params, (err, row) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(row);
                }
            });
        });
    }

    // Promise-wrapper für sqlite3.all
    all(sql, params = []) {
        return new Promise((resolve, reject) => {
            this.db.all(sql, params, (err, rows) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(rows);
                }
            });
        });
    }

    // Transaction support
    async transaction(callback) {
        await this.run('BEGIN TRANSACTION');
        try {
            const result = await callback(this);
            await this.run('COMMIT');
            return result;
        } catch (error) {
            await this.run('ROLLBACK');
            throw error;
        }
    }

    close() {
        return new Promise((resolve, reject) => {
            if (this.db) {
                this.db.close((err) => {
                    if (err) {
                        reject(err);
                    } else {
                        console.log('✓ Datenbankverbindung geschlossen');
                        resolve();
                    }
                });
            } else {
                resolve();
            }
        });
    }

    // Gesundheitscheck
    async healthCheck() {
        try {
            const result = await this.get('SELECT 1 as test');
            return result && result.test === 1;
        } catch (error) {
            console.error('Database health check failed:', error);
            return false;
        }
    }

    // Generate missing previews for existing images
    async generateMissingPreviews() {
        try {
            console.log('🔍 Checking for images without previews...');
            
            // Get all images that don't have a preview_path yet
            const imagesWithoutPreview = await this.all(`
                SELECT id, group_id, file_name, file_path 
                FROM images 
                WHERE preview_path IS NULL OR preview_path = ''
            `);

            if (imagesWithoutPreview.length === 0) {
                console.log('✓ All images have previews');
                return;
            }

            console.log(`📸 Found ${imagesWithoutPreview.length} image(s) without preview, generating...`);

            const ImagePreviewService = require('../services/ImagePreviewService');
            const fsp = require('fs').promises;
            let successCount = 0;
            let failCount = 0;

            for (const image of imagesWithoutPreview) {
                try {
                    // Check if original file exists
                    const originalPath = ImagePreviewService.getOriginalPath(image.file_name);
                    await fsp.access(originalPath);

                    // Generate preview
                    const previewFileName = ImagePreviewService._getPreviewFileName(image.file_name);
                    const previewPath = ImagePreviewService.getPreviewPath(previewFileName);
                    
                    const result = await ImagePreviewService.generatePreview(originalPath, previewPath);
                    
                    if (result.success) {
                        // Update database with preview_path
                        await this.run(`
                            UPDATE images 
                            SET preview_path = ? 
                            WHERE id = ?
                        `, [previewFileName, image.id]);
                        
                        successCount++;
                    } else {
                        console.warn(`  ⚠️  Preview generation failed for ${image.file_name}: ${result.error}`);
                        failCount++;
                    }
                } catch (error) {
                    console.warn(`  ⚠️  Could not process ${image.file_name}: ${error.message}`);
                    failCount++;
                }
            }

            console.log(`✓ Preview generation complete: ${successCount} success, ${failCount} failed`);
        } catch (error) {
            console.warn('⚠️  Preview generation check failed:', error.message);
            // Don't throw - this shouldn't prevent DB initialization
        }
    }

    /**
     * Run pending database migrations automatically
     * Migrations are SQL files in the migrations/ directory
     */
    async runMigrations() {
        try {
            console.log('🔄 Checking for database migrations...');
            
            const migrationsDir = path.join(__dirname, 'migrations');
            
            // Check if migrations directory exists
            if (!fs.existsSync(migrationsDir)) {
                console.log('  ℹ️  No migrations directory found, skipping migrations');
                return;
            }
            
            // Create migrations tracking table if it doesn't exist
            await this.run(`
                CREATE TABLE IF NOT EXISTS schema_migrations (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    migration_name TEXT UNIQUE NOT NULL,
                    applied_at DATETIME DEFAULT CURRENT_TIMESTAMP
                )
            `);
            
            // Get list of applied migrations
            const appliedMigrations = await this.all('SELECT migration_name FROM schema_migrations');
            const appliedSet = new Set(appliedMigrations.map(m => m.migration_name));
            
            // Get all migration files
            const migrationFiles = fs.readdirSync(migrationsDir)
                .filter(f => f.endsWith('.sql'))
                .sort();
            
            if (migrationFiles.length === 0) {
                console.log('  ℹ️  No migration files found');
                return;
            }
            
            let appliedCount = 0;
            
            // Run pending migrations
            for (const file of migrationFiles) {
                if (appliedSet.has(file)) {
                    continue; // Already applied
                }
                
                console.log(`  🔧 Applying migration: ${file}`);
                
                const migrationPath = path.join(migrationsDir, file);
                const sql = fs.readFileSync(migrationPath, 'utf8');
                
                try {
                    // Execute migration in a transaction
                    await this.run('BEGIN TRANSACTION');
                    
                    // Remove comments (both line and inline) to avoid sqlite parser issues
                    const cleanedSql = sql
                        .split('\n')
                        .map(line => {
                            const commentIndex = line.indexOf('--');
                            if (commentIndex !== -1) {
                                return line.substring(0, commentIndex);
                            }
                            return line;
                        })
                        .join('\n')
                        .trim();

                    if (!cleanedSql) {
                        console.warn(`  ⚠️  Migration ${file} enthält keinen ausführbaren SQL-Code, übersprungen`);
                        await this.run('COMMIT');
                        continue;
                    }

                    await this.exec(cleanedSql);
                    
                    // Record migration
                    await this.run(
                        'INSERT INTO schema_migrations (migration_name) VALUES (?)',
                        [file]
                    );
                    
                    await this.run('COMMIT');
                    appliedCount++;
                    console.log(`  ✅ Successfully applied: ${file}`);
                    
                } catch (error) {
                    await this.run('ROLLBACK');
                    console.error(`  ❌ Error applying ${file}:`, error.message);
                    throw new Error(`Migration failed: ${file} - ${error.message}`);
                }
            }
            
            if (appliedCount > 0) {
                console.log(`✓ Applied ${appliedCount} database migration(s)`);
            } else {
                console.log('✓ Database is up to date');
            }
            
        } catch (error) {
            console.error('❌ Migration error:', error.message);
            throw error;
        }
    }
}

// Singleton Instance
const dbManager = new DatabaseManager();

module.exports = dbManager;