import { Database } from 'sqlite3';

// 1. 定义 migrations 表 SQL
const createMigrationsTableSQL = `
CREATE TABLE IF NOT EXISTS migrations (
    id INTEGER PRIMARY KEY, -- 迁移的版本号
    name TEXT NOT NULL,     -- 迁移的描述性名称
    applied_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) -- 应用迁移的时间戳
);
`;

// 2. 定义迁移列表
// 注意：这里的迁移应该代表数据库模式从某个已知状态到下一个状态的变化。
// 初始模式通常在 database.ts 中通过 schema.registry.ts 创建。
// 这里的迁移应该从版本 1 开始，代表初始模式创建后的第一个变更。
interface Migration {
    id: number;
    name: string;
    sql: string; // 可以是多条 SQL 语句，用 ; 分隔。db.exec 会处理。
    check?: (db: Database) => Promise<boolean>; // 可选的前置检查函数
}

// 辅助函数：检查表是否存在
const tableExists = async (db: Database, tableName: string): Promise<boolean> => {
    return new Promise((resolve, reject) => {
        db.get("SELECT name FROM sqlite_master WHERE type='table' AND name=?", [tableName], (err, row) => {
            if (err) reject(err);
            else resolve(!!row);
        });
    });
};

// 辅助函数：检查列是否存在
const columnExists = async (db: Database, tableName: string, columnName: string): Promise<boolean> => {
    return new Promise((resolve, reject) => {
        db.all(`PRAGMA table_info(${tableName})`, (err, columns: any[]) => {
            if (err) reject(err);
            else resolve(columns.some(col => col.name === columnName));
        });
    });
};


const definedMigrations: Migration[] = [
    {
        id: 1,
        name: 'Add ssh_keys table and update connections table for SSH key management',
        check: async (db: Database): Promise<boolean> => {
            const sshKeysTableExists = await tableExists(db, 'ssh_keys');
            const connectionsTableExists = await tableExists(db, 'connections'); // 确保 connections 表存在再检查列
            const sshKeyIdColumnExists = connectionsTableExists ? await columnExists(db, 'connections', 'ssh_key_id') : false;
            // 如果 ssh_keys 表不存在 或 connections 表的 ssh_key_id 列不存在，则需要运行迁移
            return !sshKeysTableExists || !sshKeyIdColumnExists;
        },
        sql: `
            -- 创建 ssh_keys 表 (使用 IF NOT EXISTS 保证幂等性)
            CREATE TABLE IF NOT EXISTS ssh_keys (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL UNIQUE,
                encrypted_private_key TEXT NOT NULL,
                encrypted_passphrase TEXT NULL,
                created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
                updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
            );

            -- 为 connections 表添加 ssh_key_id 列及外键 (如果列不存在)
            -- 注意: 直接 ALTER TABLE 添加列在列已存在时会抛出 "duplicate column name" 错误。
            --       迁移运行器 (runMigrations) 已配置为忽略此特定错误。
            ALTER TABLE connections ADD COLUMN ssh_key_id INTEGER NULL REFERENCES ssh_keys(id) ON DELETE SET NULL;

            -- 可选: 对旧数据进行清理或更新
            -- UPDATE connections SET encrypted_private_key = NULL WHERE encrypted_private_key = ''; -- 示例
            -- UPDATE connections SET encrypted_passphrase = NULL WHERE encrypted_passphrase = ''; -- 示例
        `
    },
    // --- 未来可以添加更多迁移 ---
    // { id: 2, name: '...', sql: '...' },
];

/**
 * 运行数据库迁移。
 * 检查当前数据库版本，并按顺序应用所有新的迁移。
 * @param db 数据库实例
 */
export const runMigrations = (db: Database): Promise<void> => {
    return new Promise((resolve, reject) => {
        console.log('[Migrations] 开始检查和应用数据库迁移...');

        db.serialize(() => {
            // 步骤 1: 确保 migrations 表存在
            db.run(createMigrationsTableSQL, (err) => {
                if (err) {
                    console.error('[Migrations] 创建 migrations 表失败:', err);
                    return reject(new Error(`创建 migrations 表失败: ${err.message}`));
                }
                console.log('[Migrations] migrations 表已确保存在。');

                // 步骤 2: 获取当前数据库版本 (已应用的最大迁移 ID)
                db.get('SELECT MAX(id) as currentVersion FROM migrations', (err, row: { currentVersion: number | null }) => {
                    if (err) {
                        console.error('[Migrations] 查询当前数据库版本失败:', err);
                        return reject(new Error(`查询当前数据库版本失败: ${err.message}`));
                    }

                    const currentVersion = row?.currentVersion ?? 0; // 如果表为空或没有记录，则认为版本为 0
                    console.log(`[Migrations] 当前数据库版本: ${currentVersion}`);

                    // 步骤 3: 确定需要应用的迁移
                    const migrationsToApply = definedMigrations
                        .filter(m => m.id > currentVersion)
                        .sort((a, b) => a.id - b.id); // 确保按 ID 升序应用

                    if (migrationsToApply.length === 0) {
                        console.log('[Migrations] 数据库已是最新版本，无需迁移。');
                        return resolve();
                    }

                    console.log(`[Migrations] 发现 ${migrationsToApply.length} 个新迁移需要应用:`, migrationsToApply.map(m => `  #${m.id}: ${m.name}`));

                    // 步骤 4: 使用 async/await 方式按顺序应用迁移
                    const applyMigrationsSequentially = async () => {
                        for (const migration of migrationsToApply) { // 使用 for...of 循环
                            console.log(`[Migrations] 应用迁移 #${migration.id}: ${migration.name}...`);

                            // 开始事务
                            await new Promise<void>((resolveTx, rejectTx) => {
                                db.run('BEGIN TRANSACTION', (beginErr) => {
                                    if (beginErr) {
                                        console.error(`[Migrations] 开始迁移 #${migration.id} 事务失败:`, beginErr);
                                        rejectTx(new Error(`开始迁移 #${migration.id} 事务失败: ${beginErr.message}`));
                                    } else {
                                        resolveTx();
                                    }
                                });
                            });

                            try {
                                // 步骤 4.1: 执行前置检查 (如果存在)
                                let needsSqlExecution = true;
                                if (migration.check) {
                                    console.log(`[Migrations] 执行迁移 #${migration.id} 的前置检查...`);
                                    needsSqlExecution = await migration.check(db);
                                    console.log(`[Migrations] 迁移 #${migration.id} 前置检查结果: ${needsSqlExecution ? '需要执行 SQL' : '跳过 SQL 执行'}`);
                                }

                                if (needsSqlExecution) {
                                    // 步骤 4.2: 执行迁移 SQL
                                    console.log(`[Migrations] 执行迁移 #${migration.id} 的 SQL...`);
                                    await new Promise<void>((resolveSql, rejectSql) => {
                                        db.exec(migration.sql, (execErr) => {
                                            if (execErr) {
                                                // 特别处理 "duplicate column name" 错误
                                                if (execErr.message.includes('duplicate column name')) {
                                                    console.warn(`[Migrations] 迁移 #${migration.id} SQL 执行时出现 'duplicate column name' 错误，视为可接受并继续。`);
                                                    resolveSql();
                                                } else {
                                                    console.error(`[Migrations] 执行迁移 #${migration.id} SQL 失败:`, execErr);
                                                    rejectSql(execErr);
                                                }
                                            } else {
                                                resolveSql();
                                            }
                                        });
                                    });
                                }

                                // 步骤 4.3: 记录迁移到 migrations 表
                                console.log(`[Migrations] 记录迁移 #${migration.id} 到 migrations 表...`);
                                const insertSQL = 'INSERT INTO migrations (id, name, applied_at) VALUES (?, ?, strftime(\'%s\', \'now\'))';
                                await new Promise<void>((resolveInsert, rejectInsert) => {
                                    db.run(insertSQL, [migration.id, migration.name], (insertErr) => {
                                        if (insertErr) {
                                            console.error(`[Migrations] 记录迁移 #${migration.id} 到 migrations 表失败:`, insertErr);
                                            rejectInsert(insertErr);
                                        } else {
                                            resolveInsert();
                                        }
                                    });
                                });

                                // 步骤 4.4: 提交事务
                                console.log(`[Migrations] 提交迁移 #${migration.id} 事务...`);
                                await new Promise<void>((resolveCommit, rejectCommit) => {
                                    db.run('COMMIT', (commitErr) => {
                                        if (commitErr) {
                                            console.error(`[Migrations] 提交迁移 #${migration.id} 事务失败:`, commitErr);
                                            rejectCommit(commitErr);
                                        } else {
                                            console.log(`[Migrations] 迁移 #${migration.id}: ${migration.name} 应用成功 (SQL 可能已跳过)。`);
                                            resolveCommit();
                                        }
                                    });
                                });

                            } catch (migrationStepError: any) {
                                // 捕获 check, exec, insert 或 commit 中的任何错误
                                console.error(`[Migrations] 迁移 #${migration.id} 步骤失败，正在回滚事务...`);
                                await new Promise<void>((resolveRollback) => { // No reject needed for rollback itself
                                    db.run('ROLLBACK', (rollbackErr) => {
                                        if (rollbackErr) console.error(`[Migrations] 回滚迁移 #${migration.id} 事务失败:`, rollbackErr);
                                        // 拒绝整个迁移过程
                                        reject(new Error(`迁移 #${migration.id} 失败: ${migrationStepError.message}`));
                                        resolveRollback(); // Indicate rollback attempt finished
                                    });
                                });
                                return; // 停止应用后续迁移
                            }
                        } 

                        // 所有迁移成功应用
                        console.log('[Migrations] 所有新迁移已成功应用！');
                        resolve();

                    };

                    // 开始按顺序应用迁移
                    applyMigrationsSequentially().catch(reject); // 将 applyMigrationsSequentially 的拒绝传递给外层 Promise

                });
            });
        });
    });
};
