import { Sequelize, DataTypes } from 'sequelize';
import dotenv from 'dotenv';

dotenv.config();

// Optionales Performance-Logging (aktivierbar per ENV)
// - SQL_BENCHMARK=1: Sequelize liefert Query-Timing (ms) an logger
// - SQL_SLOW_MS=200: Logge nur Queries ab dieser Dauer (wenn SQL_LOG_ALL nicht gesetzt)
// - SQL_LOG_ALL=1: Logge alle Queries (auch ohne benchmark)
const SQL_BENCHMARK = process.env.SQL_BENCHMARK === '1';
const SQL_LOG_ALL = process.env.SQL_LOG_ALL === '1';
const SQL_SLOW_MS = Number.parseInt(process.env.SQL_SLOW_MS || '200', 10);
const sqlLogger = (sql, timing) => {
    // Sequelize ruft logging(sql) oder logging(sql, timing) abhängig von benchmark auf.
    if (!SQL_BENCHMARK) {
        if (SQL_LOG_ALL) console.log(sql);
        return;
    }
    const ms = typeof timing === 'number' ? timing : 0;
    if (SQL_LOG_ALL || ms >= SQL_SLOW_MS) {
        console.log(`🛢️  SQL ${ms}ms: ${sql}`);
    }
};

// Validiere Umgebungsvariablen
const dbName = process.env.DB_NAME;
const dbUser = process.env.DB_USER;
const dbPass = process.env.DB_PASS || ''; // Fallback auf leeren String
const dbHost = process.env.DB_HOST;

console.log('Database configuration:');
console.log('DB_NAME:', dbName);
console.log('DB_USER:', dbUser);
console.log('DB_PASS:', dbPass ? '[SET]' : '[NOT SET]');
console.log('DB_HOST:', dbHost);

if (!dbName || !dbUser || !dbHost) {
    throw new Error('Missing required database environment variables: DB_NAME, DB_USER, or DB_HOST');
}

const sequelize = new Sequelize(dbName, dbUser, dbPass, {
    host: dbHost,
    dialect: 'postgres',
    define: {
        timestamps: false,
        underscored: true  // WICHTIG: Alle Datenbankfelder im snake_case Format
    },
    benchmark: SQL_BENCHMARK,
    logging: sqlLogger,
});

const createSchemas = async () => {
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS community');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS logs');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS type');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS service');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS forum');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_data');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_type');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_predefine');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_log');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS chat');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS match3');
    await sequelize.query('CREATE SCHEMA IF NOT EXISTS taxi');
};

const initializeDatabase = async () => {
    await createSchemas();
    
    // Aktiviere die pgcrypto Erweiterung für die digest() Funktion
    try {
        await sequelize.query('CREATE EXTENSION IF NOT EXISTS pgcrypto;');
        console.log('✅ pgcrypto Erweiterung aktiviert');
    } catch (error) {
        console.warn('⚠️  Konnte pgcrypto Erweiterung nicht aktivieren:', error.message);
        // Fortfahren, da die Erweiterung möglicherweise bereits aktiviert ist
    }
    
    // Modelle nur laden, aber an dieser Stelle NICHT syncen.
    // Das Syncing (inkl. alter: true bei Bedarf) wird anschließend zentral
    // über syncModelsWithUpdates()/syncModelsAlways gesteuert.
    await import('../models/index.js');
};

const syncModels = async (models) => {
    for (const model of Object.values(models)) { 
        // Verwende force: false und alter: false, um Constraints nicht neu zu erstellen
        // Nur beim ersten Mal oder bei expliziten Schema-Änderungen sollte alter: true verwendet werden
        await model.sync({ alter: false, force: false });
    }
};

// Intelligente Schema-Synchronisation - prüft ob Updates nötig sind
const syncModelsWithUpdates = async (models) => {
    // Prüfe ob wir im Entwicklungsmodus sind
    if (process.env.STAGE !== 'dev') {
        console.log('🚫 Nicht im Entwicklungsmodus - überspringe Schema-Updates');
        console.log('📊 Aktueller Stage:', process.env.STAGE || 'nicht gesetzt');
        console.log('💡 Setze STAGE=dev in der .env Datei für automatische Schema-Updates');
        console.log('🔒 Sicherheitsmodus: Schema-Updates sind deaktiviert');
        
        // Normale Synchronisation ohne Updates
        for (const model of Object.values(models)) { 
            await model.sync({ alter: false, force: false });
        }
        return;
    }

    // Zusätzliche Sicherheitsabfrage für Produktionsumgebungen
    if (process.env.NODE_ENV === 'production' && process.env.STAGE !== 'dev') {
        console.log('🚨 PRODUKTIONSWARNUNG: Schema-Updates sind in Produktionsumgebungen deaktiviert!');
        console.log('🔒 Verwende nur normale Synchronisation ohne Schema-Änderungen');
        
        for (const model of Object.values(models)) { 
            await model.sync({ alter: false, force: false });
        }
        return;
    }

    console.log('🔍 Entwicklungsmodus aktiv - prüfe ob Schema-Updates nötig sind...');
    
    try {
        // Prüfe ob neue Felder existieren müssen
        const needsUpdate = await checkSchemaUpdates(models);
        
        if (needsUpdate) {
            console.log('🔄 Schema-Updates nötig - verwende alter: true');
            for (const model of Object.values(models)) { 
                // constraints: false verhindert, dass Sequelize Foreign Keys automatisch erstellt
                await model.sync({ alter: true, force: false, constraints: false });
            }
            console.log('✅ Schema-Updates abgeschlossen');
        } else {
            console.log('✅ Keine Schema-Updates nötig - verwende alter: false');
            for (const model of Object.values(models)) { 
                await model.sync({ alter: false, force: false });
            }
        }
    } catch (error) {
        console.error('❌ Fehler bei Schema-Synchronisation:', error);
        // Fallback: Normale Synchronisation ohne Updates
        console.log('🔄 Fallback: Normale Synchronisation ohne Updates');
        for (const model of Object.values(models)) { 
            await model.sync({ alter: false, force: false });
        }
    }
};

// Prüft ob Schema-Updates nötig sind
const checkSchemaUpdates = async (models) => {
    try {
        console.log('🔍 Prüfe alle Schemas auf Updates...');
        
        // Alle verfügbaren Schemas
        const schemas = [
            'community', 'logs', 'type', 'service', 'forum', 
            'falukant_data', 'falukant_type', 'falukant_predefine', 'falukant_log', 
            'chat', 'match3', 'taxi'
        ];
        
        let needsUpdate = false;
        
        // Prüfe jedes Schema
        for (const schema of schemas) {
            const schemaNeedsUpdate = await checkSchemaForUpdates(schema, models);
            if (schemaNeedsUpdate) {
                needsUpdate = true;
            }
        }
        
        return needsUpdate;
    } catch (error) {
        console.error('❌ Fehler bei Schema-Prüfung:', error);
        return false; // Im Zweifelsfall: Keine Updates
    }
};

// Prüft ein spezifisches Schema auf Updates
const checkSchemaForUpdates = async (schemaName, models) => {
    try {
        console.log(`🔍 Prüfe Schema: ${schemaName}`);
        
        // Hole alle Tabellen in diesem Schema
        const tables = await sequelize.query(`
            SELECT table_name 
            FROM information_schema.tables 
            WHERE table_schema = $1
            ORDER BY table_name
        `, { 
            bind: [schemaName],
            type: sequelize.QueryTypes.SELECT 
        });
        
        if (tables.length === 0) {
            console.log(`  📊 Schema ${schemaName}: Keine Tabellen gefunden`);
            return false;
        }
        
        console.log(`  📊 Schema ${schemaName}: ${tables.length} Tabellen gefunden`);
        
        // Prüfe jede Tabelle auf Updates
        for (const table of tables) {
            const tableName = table.table_name;
            const tableNeedsUpdate = await checkTableForUpdates(schemaName, tableName, models);
            if (tableNeedsUpdate) {
                console.log(`  🔄 Tabelle ${tableName} braucht Updates`);
                return true;
            }
        }
        
        // Prüfe auf fehlende Tabellen (neue Models)
        const missingTables = await checkForMissingTables(schemaName, models);
        if (missingTables.length > 0) {
            console.log(`  🔄 Neue Tabellen gefunden: ${missingTables.join(', ')}`);
            return true;
        }
        
        console.log(`  ✅ Schema ${schemaName}: Keine Updates nötig`);
        return false;
        
    } catch (error) {
        console.error(`❌ Fehler beim Prüfen von Schema ${schemaName}:`, error);
        return false;
    }
};

// Prüft auf fehlende Tabellen (neue Models)
const checkForMissingTables = async (schemaName, models) => {
    try {
        const missingTables = [];
        
        // Hole alle erwarteten Tabellen aus den Models
        for (const [modelName, model] of Object.entries(models)) {
            if (model._schema === schemaName) {
                const tableExists = await sequelize.query(`
                    SELECT EXISTS (
                        SELECT FROM information_schema.tables 
                        WHERE table_schema = $1 
                        AND table_name = $2
                    );
                `, { 
                    bind: [schemaName, model.tableName],
                    type: sequelize.QueryTypes.SELECT 
                });
                
                if (!tableExists[0]?.exists) {
                    missingTables.push(model.tableName);
                }
            }
        }
        
        return missingTables;
    } catch (error) {
        console.error(`❌ Fehler beim Prüfen fehlender Tabellen:`, error);
        return [];
    }
};

// Prüft eine spezifische Tabelle auf Updates
const checkTableForUpdates = async (schemaName, tableName, models) => {
    try {
        // Finde das entsprechende Model
        const model = findModelForTable(schemaName, tableName, models);
        if (!model) {
            console.log(`    ⚠️  Kein Model für Tabelle ${schemaName}.${tableName} gefunden`);
            return false;
        }
        
        // Hole aktuelle Spalten der Tabelle
        const currentColumns = await sequelize.query(`
            SELECT column_name, data_type, is_nullable, column_default
            FROM information_schema.columns 
            WHERE table_schema = $1 
            AND table_name = $2
            ORDER BY ordinal_position
        `, { 
            bind: [schemaName, tableName],
            type: sequelize.QueryTypes.SELECT 
        });
        
        // Hole erwartete Spalten aus dem Model
        const expectedColumns = Object.keys(model.rawAttributes);
        
        // Vergleiche aktuelle und erwartete Spalten
        const missingColumns = expectedColumns.filter(expectedCol => {
            return !currentColumns.some(currentCol => 
                currentCol.column_name === expectedCol
            );
        });
        
        if (missingColumns.length > 0) {
            console.log(`    📊 Fehlende Spalten in ${tableName}: ${missingColumns.join(', ')}`);
            return true;
        }
        
        // Prüfe auf geänderte Spalten-Typen oder Constraints
        for (const expectedCol of expectedColumns) {
            const currentCol = currentColumns.find(col => col.column_name === expectedCol);
            if (currentCol) {
                const needsUpdate = await checkColumnForUpdates(
                    schemaName, tableName, expectedCol, currentCol, model.rawAttributes[expectedCol]
                );
                if (needsUpdate) {
                    return true;
                }
            }
        }
        
        return false;
        
    } catch (error) {
        console.error(`❌ Fehler beim Prüfen von Tabelle ${schemaName}.${tableName}:`, error);
        return false;
    }
};

// Prüft eine spezifische Spalte auf Updates
const checkColumnForUpdates = async (schemaName, tableName, columnName, currentColumn, expectedAttribute) => {
    try {
        // Prüfe Datentyp-Änderungen
        if (currentColumn.data_type !== getExpectedDataType(expectedAttribute)) {
            console.log(`    🔄 Spalte ${columnName}: Datentyp geändert (${currentColumn.data_type} → ${getExpectedDataType(expectedAttribute)})`);
            return true;
        }
        
        // Prüfe NULL/NOT NULL Änderungen
        const currentNullable = currentColumn.is_nullable === 'YES';
        const expectedNullable = expectedAttribute.allowNull !== false;
        if (currentNullable !== expectedNullable) {
            console.log(`    🔄 Spalte ${columnName}: NULL-Constraint geändert (${currentNullable} → ${expectedNullable})`);
            return true;
        }
        
        // Prüfe Standardwert-Änderungen
        if (expectedAttribute.defaultValue !== undefined && 
            currentColumn.column_default !== getExpectedDefaultValue(expectedAttribute.defaultValue)) {
            console.log(`    🔄 Spalte ${columnName}: Standardwert geändert`);
            return true;
        }
        
        return false;
        
    } catch (error) {
        console.error(`❌ Fehler beim Prüfen von Spalte ${columnName}:`, error);
        return false;
    }
};

// Hilfsfunktion: Findet Model für eine Tabelle
const findModelForTable = (schemaName, tableName, models) => {
    // Suche nach dem Model basierend auf Schema und Tabellenname
    for (const [modelName, model] of Object.entries(models)) {
        if (model.tableName === tableName && 
            model._schema === schemaName) {
            return model;
        }
    }
    return null;
};

// Hilfsfunktion: Konvertiert Sequelize-Datentyp zu PostgreSQL-Datentyp
const getExpectedDataType = (attribute) => {
    if (!attribute || !attribute.type) return 'text';
    const type = attribute.type;

    // Direktklassentypen in Sequelize sind Funktionen/Klassen; "instanceof" funktioniert bei Wrappern wie DataTypes.INTEGER() nicht immer.
    // Deshalb vergleichen wir über den .key wenn verfügbar.
    const key = type.key || type.constructor?.key;
    switch (key) {
        case 'INTEGER': return 'integer';
        case 'STRING': return 'character varying';
        case 'TEXT': return 'text';
        case 'BOOLEAN': return 'boolean';
        case 'DATE': return 'timestamp without time zone';
        case 'JSON': return 'json';
        case 'DECIMAL': return 'numeric';
        default:
            return 'text';
    }
};

// Hilfsfunktion: Konvertiert Sequelize-Default zu PostgreSQL-Default
const getExpectedDefaultValue = (defaultValue) => {
    if (defaultValue === null) return null;
    if (typeof defaultValue === 'string') return `'${defaultValue}'`;
    if (typeof defaultValue === 'number') return defaultValue.toString();
    if (typeof defaultValue === 'boolean') return defaultValue.toString();
    if (defaultValue === sequelize.literal('CURRENT_TIMESTAMP')) return 'CURRENT_TIMESTAMP';
    
    // Fallback
    return defaultValue?.toString() || null;
};

// Separate Funktion für Schema-Updates (nur bei Bedarf aufrufen)
const updateSchema = async (models) => {
    console.log('🔄 Aktualisiere Datenbankschema...');
    for (const model of Object.values(models)) { 
        // constraints: false verhindert, dass Sequelize Foreign Keys automatisch erstellt
        await model.sync({ alter: true, force: false, constraints: false });
    }
    console.log('✅ Datenbankschema aktualisiert');
};

async function updateFalukantUserMoney(falukantUserId, moneyChange, activity, changedBy = null, transaction = null) {
    try {
        const result = await sequelize.query(
            `SELECT falukant_data.update_money(
                :falukantUserId, 
                :moneyChange, 
                :activity, 
                :changedBy
            )`,
            {
                replacements: {
                    falukantUserId,
                    moneyChange,
                    activity,
                    changedBy,
                },
                type: sequelize.QueryTypes.SELECT,
                transaction: transaction || undefined,
            }
        );
        return { 
            success: true, 
            message: 'Money updated successfully', 
            result 
        };
    } catch (error) {
        console.error('Error updating money:', error);
        return { 
            success: false, 
            message: error.message 
        };
    }
}

// Immer Schema-Updates (für Deployment)
const syncModelsAlways = async (models) => {
    console.log('🔍 Deployment-Modus: Führe immer Schema-Updates durch...');
    
    try {
        for (const model of Object.values(models)) {
            // Temporarily remove VIRTUAL fields before sync to prevent sync errors
            const originalAttributes = model.rawAttributes;
            const virtualFields = {};
            
            // Find and temporarily remove VIRTUAL fields
            // Check multiple ways to identify VIRTUAL fields
            for (const [key, attr] of Object.entries(originalAttributes)) {
                // Check if it's a VIRTUAL field by checking the type
                let isVirtual = false;
                
                if (attr.type) {
                    // Method 1: Check if type key is VIRTUAL (most reliable)
                    if (attr.type.key === 'VIRTUAL') {
                        isVirtual = true;
                    }
                    // Method 2: Direct comparison with DataTypes.VIRTUAL
                    else if (attr.type === DataTypes.VIRTUAL) {
                        isVirtual = true;
                    }
                    // Method 3: Check toString representation
                    else if (typeof attr.type.toString === 'function') {
                        const typeStr = attr.type.toString();
                        if (typeStr === 'VIRTUAL' || typeStr.includes('VIRTUAL')) {
                            isVirtual = true;
                        }
                    }
                    // Method 4: Check constructor name
                    else if (attr.type.constructor && attr.type.constructor.name === 'VIRTUAL') {
                        isVirtual = true;
                    }
                }
                
                // Also check if field has a getter but no setter and no field mapping (common pattern for VIRTUAL fields)
                // But only if it doesn't have a 'field' property, which means it's not mapped to a database column
                if (!isVirtual && attr.get && !attr.set && !attr.field) {
                    // This might be a VIRTUAL field, but be careful not to remove real fields
                    // Only remove if we're certain it's VIRTUAL
                }
                
                if (isVirtual) {
                    virtualFields[key] = attr;
                    delete model.rawAttributes[key];
                    console.log(`  ⚠️  Temporarily removed VIRTUAL field: ${key} from model ${model.name}`);
                }
            }
            
            // Special handling for Notification model: ensure characterName VIRTUAL field is removed
            // This is a workaround for Sequelize bug where it confuses characterName (VIRTUAL) with character_name (STRING)
            if (model.name === 'Notification' && model.rawAttributes.characterName) {
                if (!virtualFields.characterName) {
                    virtualFields.characterName = model.rawAttributes.characterName;
                    delete model.rawAttributes.characterName;
                    console.log(`  ⚠️  Explicitly removed VIRTUAL field: characterName from Notification model`);
                }
            }
            
            // constraints: false wird von Sequelize ignoriert wenn Associations vorhanden sind
            // Wir müssen die Associations temporär entfernen, um Foreign Keys zu verhindern
            const originalAssociations = model.associations ? { ...model.associations } : {};
            const associationKeys = Object.keys(originalAssociations);
            
            try {
                // Entferne temporär alle Associations, damit Sequelize keine Foreign Keys erstellt
                // Dies muss innerhalb des try Blocks sein, damit die Wiederherstellung im finally Block garantiert ist
                if (associationKeys.length > 0) {
                    console.log(`  ⚠️  Temporarily removing ${associationKeys.length} associations from ${model.name} to prevent FK creation`);
                    // Lösche alle Associations temporär
                    for (const key of associationKeys) {
                        delete model.associations[key];
                    }
                }
                
                // Entferne bestehende Foreign Keys vor dem Sync, damit Sequelize sie nicht aktualisiert
                try {
                    const tableName = model.tableName;
                    // Schema kann eine Funktion sein, daher prüfen wir model.options.schema direkt
                    const schema = model.options?.schema || 'public';
                    
                    console.log(`  🔍 Checking for foreign keys in ${schema}.${tableName}...`);
                    const foreignKeys = await sequelize.query(`
                        SELECT tc.constraint_name
                        FROM information_schema.table_constraints AS tc
                        WHERE tc.constraint_type = 'FOREIGN KEY'
                        AND tc.table_name = :tableName
                        AND tc.table_schema = :schema
                    `, {
                        replacements: { tableName, schema },
                        type: sequelize.QueryTypes.SELECT
                    });
                    
                    if (foreignKeys && foreignKeys.length > 0) {
                        console.log(`  ⚠️  Found ${foreignKeys.length} existing foreign keys:`, foreignKeys.map(fk => fk.constraint_name).join(', '));
                        console.log(`  ⚠️  Removing ${foreignKeys.length} existing foreign keys from ${model.name} (schema: ${schema}) before sync`);
                        for (const fk of foreignKeys) {
                            console.log(`  🗑️  Dropping constraint: ${fk.constraint_name}`);
                            await sequelize.query(`
                                ALTER TABLE "${schema}"."${tableName}" 
                                DROP CONSTRAINT IF EXISTS "${fk.constraint_name}" CASCADE
                            `);
                        }
                        console.log(`  ✅ All foreign keys removed for ${model.name}`);
                    } else {
                        console.log(`  ✅ No foreign keys found for ${model.name}`);
                    }
                } catch (fkError) {
                    console.warn(`  ⚠️  Could not remove foreign keys for ${model.name}:`, fkError.message);
                    console.warn(`  ⚠️  Error details:`, fkError);
                }
                
                console.log(`  🔄 Syncing model ${model.name} with constraints: false`);
                try {
                    // Versuche doppelte pg_description Einträge vor dem Sync zu bereinigen
                    // Hinweis: Benötigt Superuser-Rechte oder spezielle Berechtigungen
                    try {
                        const tableName = model.tableName;
                        const schema = model.options?.schema || 'public';
                        // Verwende direkte Parameter-Einsetzung, da DO $$ keine Parameterbindung unterstützt
                        // Die Parameter sind sicher, da sie von Sequelize-Modell-Eigenschaften kommen
                        await sequelize.query(`
                            DELETE FROM pg_catalog.pg_description d1
                            WHERE d1.objoid IN (
                                SELECT c.oid
                                FROM pg_catalog.pg_class c
                                JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
                                WHERE c.relname = '${tableName.replace(/'/g, "''")}'
                                AND n.nspname = '${schema.replace(/'/g, "''")}'
                            )
                            AND EXISTS (
                                SELECT 1
                                FROM pg_catalog.pg_description d2
                                WHERE d2.objoid = d1.objoid
                                AND d2.objsubid = d1.objsubid
                                AND d2.ctid < d1.ctid
                            )
                        `);
                    } catch (descError) {
                        // Ignoriere Berechtigungsfehler - das ist normal, wenn der Benutzer keine Superuser-Rechte hat
                        if (descError.message && descError.message.includes('Berechtigung')) {
                            console.log(`  ℹ️  Cannot clean up duplicate pg_description entries (requires superuser privileges): ${model.name}`);
                        } else {
                            console.warn(`  ⚠️  Could not clean up duplicate pg_description entries for ${model.name}:`, descError.message);
                        }
                    }
                    
                    await model.sync({ alter: true, force: false, constraints: false });
                } catch (syncError) {
                    // Wenn Sequelize einen "mehr als eine Zeile" Fehler hat, überspringe das Model
                    // Dies kann durch doppelte pg_description Einträge oder mehrere Tabellen mit demselben Namen verursacht werden
                    if (syncError.message && (syncError.message.includes('mehr als eine Zeile') || syncError.message.includes('more than one row'))) {
                        const tableName = model.tableName;
                        const schema = model.options?.schema || 'public';
                        console.error(`  ❌ Cannot sync ${model.name} (${schema}.${tableName}) due to Sequelize describeTable error`);
                        console.error(`  ❌ This is likely caused by multiple tables with the same name in different schemas`);
                        console.error(`  ❌ or duplicate pg_description entries (requires superuser to fix)`);
                        console.error(`  ⚠️  Skipping sync for ${model.name} - Schema is likely already correct`);
                        // Überspringe dieses Model und fahre mit dem nächsten fort
                        continue;
                    }
                    // Wenn eine referenzierte Tabelle noch nicht existiert, erstelle die Tabelle ohne Foreign Key
                    else if (syncError.message && (syncError.message.includes('existiert nicht') || syncError.message.includes('does not exist') || syncError.message.includes('Relation'))) {
                        const tableName = model.tableName;
                        const schema = model.options?.schema || 'public';
                        console.warn(`  ⚠️  Cannot create ${model.name} (${schema}.${tableName}) with Foreign Key - referenced table does not exist yet`);
                        console.warn(`  ⚠️  Attempting to create table without Foreign Key constraint...`);
                        
                        try {
                            // Prüfe, ob die Tabelle bereits existiert
                            const [tableExists] = await sequelize.query(`
                                SELECT EXISTS (
                                    SELECT 1 FROM information_schema.tables 
                                    WHERE table_schema = :schema 
                                    AND table_name = :tableName
                                ) as exists
                            `, {
                                replacements: { schema, tableName },
                                type: sequelize.QueryTypes.SELECT
                            });
                            
                            if (tableExists && tableExists.exists) {
                                console.log(`  ℹ️  Table ${schema}.${tableName} already exists, skipping creation`);
                                continue;
                            }
                            
                            // Erstelle die Tabelle manuell ohne Foreign Key
                            // Verwende queryInterface.createTable mit den Attributen, aber ohne Foreign Keys
                            const queryInterface = sequelize.getQueryInterface();
                            const attributes = {};
                            
                            // Kopiere alle Attribute aus dem Model, aber entferne references
                            for (const [key, attr] of Object.entries(model.rawAttributes)) {
                                attributes[key] = { ...attr };
                                // Entferne references, damit kein Foreign Key erstellt wird
                                if (attributes[key].references) {
                                    delete attributes[key].references;
                                }
                            }
                            
                            // Erstelle die Tabelle mit queryInterface.createTable ohne Foreign Keys
                            await queryInterface.createTable(tableName, attributes, { 
                                schema,
                                // Stelle sicher, dass keine Foreign Keys erstellt werden
                                charset: model.options?.charset,
                                collate: model.options?.collate
                            });
                            console.log(`  ✅ Table ${schema}.${tableName} created successfully without Foreign Key`);
                        } catch (createError) {
                            console.error(`  ❌ Failed to create table ${schema}.${tableName} without Foreign Key:`, createError.message);
                            console.error(`  ⚠️  Skipping ${model.name} - will retry after dependencies are created`);
                            // Überspringe dieses Model und fahre mit dem nächsten fort
                            continue;
                        }
                    }
                    // Wenn Sequelize einen Foreign Key Constraint Fehler hat, entferne verwaiste Einträge oder überspringe das Model
                    else if (syncError.name === 'SequelizeForeignKeyConstraintError' || (syncError.message && (syncError.message.includes('FOREIGN KEY') || syncError.message.includes('Fremdschlüssel')))) {
                        const tableName = model.tableName;
                        const schema = model.options?.schema || 'public';
                        console.error(`  ❌ Cannot sync ${model.name} (${schema}.${tableName}) due to Foreign Key Constraint Error`);
                        console.error(`  ❌ Detail: ${syncError.parent?.detail || syncError.message}`);
                        console.error(`  ⚠️  This usually means there are orphaned records. Cleanup should have removed them.`);
                        console.error(`  ⚠️  Skipping sync for ${model.name} - please check and fix orphaned records manually`);
                        // Überspringe dieses Model und fahre mit dem nächsten fort
                        continue;
                    }
                    // Wenn Sequelize versucht, Foreign Keys zu erstellen, entferne sie nach dem Fehler
                    else if (syncError.message && syncError.message.includes('REFERENCES')) {
                        console.log(`  ⚠️  Sequelize tried to create FK despite constraints: false, removing any created FKs...`);
                        try {
                            const tableName = model.tableName;
                            const schema = model.options?.schema || 'public';
                            const foreignKeys = await sequelize.query(`
                                SELECT tc.constraint_name
                                FROM information_schema.table_constraints AS tc
                                WHERE tc.constraint_type = 'FOREIGN KEY'
                                AND tc.table_name = :tableName
                                AND tc.table_schema = :schema
                            `, {
                                replacements: { tableName, schema },
                                type: sequelize.QueryTypes.SELECT
                            });
                            
                            if (foreignKeys && foreignKeys.length > 0) {
                                for (const fk of foreignKeys) {
                                    await sequelize.query(`
                                        ALTER TABLE "${schema}"."${tableName}" 
                                        DROP CONSTRAINT IF EXISTS "${fk.constraint_name}" CASCADE
                                    `);
                                }
                            }
                            // Versuche Sync erneut ohne Foreign Keys
                            console.log(`  🔄 Retrying sync without foreign keys...`);
                            await model.sync({ alter: true, force: false, constraints: false });
                        } catch (retryError) {
                            console.error(`  ❌ Retry failed:`, retryError.message);
                            console.error(`  ❌ Original sync error:`, syncError.message);
                            // Kombiniere beide Fehler für besseres Debugging
                            const combinedError = new Error(`Sync failed: ${syncError.message}. Retry also failed: ${retryError.message}`);
                            combinedError.originalError = syncError;
                            combinedError.retryError = retryError;
                            throw combinedError;
                        }
                    } else {
                        throw syncError;
                    }
                }
                
                // Entferne alle Foreign Keys, die Sequelize möglicherweise trotzdem erstellt hat
                try {
                    const tableName = model.tableName;
                    const schema = model.options?.schema || 'public';
                    const foreignKeys = await sequelize.query(`
                        SELECT tc.constraint_name
                        FROM information_schema.table_constraints AS tc
                        WHERE tc.constraint_type = 'FOREIGN KEY'
                        AND tc.table_name = :tableName
                        AND tc.table_schema = :schema
                    `, {
                        replacements: { tableName, schema },
                        type: sequelize.QueryTypes.SELECT
                    });
                    
                    if (foreignKeys && foreignKeys.length > 0) {
                        console.log(`  ⚠️  Sequelize created ${foreignKeys.length} foreign keys despite constraints: false, removing them...`);
                        for (const fk of foreignKeys) {
                            await sequelize.query(`
                                ALTER TABLE "${schema}"."${tableName}" 
                                DROP CONSTRAINT IF EXISTS "${fk.constraint_name}" CASCADE
                            `);
                        }
                    }
                } catch (fkError) {
                    console.warn(`  ⚠️  Could not check/remove foreign keys after sync:`, fkError.message);
                }
            } finally {
                // Stelle die Associations wieder her (IMMER, auch bei Fehlern)
                if (associationKeys.length > 0) {
                    console.log(`  ✅ Restoring ${associationKeys.length} associations for ${model.name}`);
                    model.associations = originalAssociations;
                }
                
                // Restore VIRTUAL fields after sync
                for (const [key, attr] of Object.entries(virtualFields)) {
                    model.rawAttributes[key] = attr;
                }
            }
        }
        console.log('✅ Schema-Updates für alle Models abgeschlossen');
    } catch (error) {
        console.error('❌ Fehler bei Schema-Updates:', error);
        throw error;
    }
};

export { sequelize, initializeDatabase, syncModels, syncModelsWithUpdates, syncModelsAlways, updateSchema, updateFalukantUserMoney };
