"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const globals_1 = require("@jest/globals");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const database_1 = require("../../utils/database");
const migrationHealthCheck_1 = require("../../utils/migrationHealthCheck");
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
(0, globals_1.describe)('MigrationHealthCheck', () => {
    let tempDir;
    let dbPath;
    let dbManager;
    let healthCheck;
    (0, globals_1.beforeEach)(() => {
        // Create temporary directory for test database
        tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-test-'));
        dbPath = path.join(tempDir, 'test.db');
    });
    (0, globals_1.afterEach)(() => {
        // Clean up
        if (dbManager) {
            dbManager.close();
        }
        // Remove temporary directory
        fs.rmSync(tempDir, { recursive: true, force: true });
    });
    (0, globals_1.describe)('Missing column detection', () => {
        (0, globals_1.it)('should detect missing metadata column in context_items table', () => {
            // Create a database with old schema (missing metadata column)
            const db = new better_sqlite3_1.default(dbPath);
            db.exec(`
        CREATE TABLE sessions (
          id TEXT PRIMARY KEY,
          name TEXT,
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        );
        
        CREATE TABLE context_items (
          id TEXT PRIMARY KEY,
          session_id TEXT NOT NULL,
          key TEXT NOT NULL,
          value TEXT NOT NULL,
          category TEXT,
          priority TEXT DEFAULT 'normal',
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
          FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
        );
      `);
            // Create health check without initializing DatabaseManager to avoid auto-fix
            const dbManager = new better_sqlite3_1.default(dbPath);
            healthCheck = new migrationHealthCheck_1.MigrationHealthCheck({ getDatabase: () => dbManager });
            const result = healthCheck.runHealthCheck();
            db.close();
            dbManager.close();
            // Should detect missing columns
            (0, globals_1.expect)(result.issues.length).toBeGreaterThan(0);
            const metadataIssue = result.issues.find(issue => issue.table === 'context_items' && issue.issue.includes('metadata'));
            (0, globals_1.expect)(metadataIssue).toBeDefined();
            (0, globals_1.expect)(metadataIssue?.severity).toBe('error');
            (0, globals_1.expect)(metadataIssue?.fix).toContain('ALTER TABLE context_items ADD COLUMN metadata TEXT');
        });
        (0, globals_1.it)('should detect multiple missing columns', () => {
            // Create a database with very old schema
            const db = new better_sqlite3_1.default(dbPath);
            db.exec(`
        CREATE TABLE sessions (
          id TEXT PRIMARY KEY,
          name TEXT,
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        );
        
        CREATE TABLE context_items (
          id TEXT PRIMARY KEY,
          session_id TEXT NOT NULL,
          key TEXT NOT NULL,
          value TEXT NOT NULL,
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
          FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
        );
      `);
            // Create health check without initializing DatabaseManager
            const dbManager = new better_sqlite3_1.default(dbPath);
            healthCheck = new migrationHealthCheck_1.MigrationHealthCheck({ getDatabase: () => dbManager });
            const result = healthCheck.runHealthCheck();
            db.close();
            dbManager.close();
            // Should detect multiple missing columns
            const missingColumns = ['category', 'priority', 'metadata', 'size'];
            for (const column of missingColumns) {
                const issue = result.issues.find(i => i.table === 'context_items' && i.issue.includes(column));
                (0, globals_1.expect)(issue).toBeDefined();
            }
            // updated_at might exist depending on schema version, check separately
            const hasUpdatedAt = result.issues.some(i => i.table === 'context_items' && i.issue.includes('updated_at'));
            if (hasUpdatedAt) {
                (0, globals_1.expect)(result.issues.length).toBeGreaterThanOrEqual(missingColumns.length + 1);
            }
            else {
                (0, globals_1.expect)(result.issues.length).toBeGreaterThanOrEqual(missingColumns.length);
            }
        });
    });
    (0, globals_1.describe)('Auto-fix functionality', () => {
        (0, globals_1.it)('should successfully add missing columns', () => {
            // Create a database with old schema
            const db = new better_sqlite3_1.default(dbPath);
            db.exec(`
        CREATE TABLE sessions (
          id TEXT PRIMARY KEY,
          name TEXT,
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        );
        
        CREATE TABLE context_items (
          id TEXT PRIMARY KEY,
          session_id TEXT NOT NULL,
          key TEXT NOT NULL,
          value TEXT NOT NULL,
          category TEXT,
          priority TEXT DEFAULT 'normal',
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
          FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
        );
      `);
            db.close();
            // Create proper DatabaseManager instance but prevent auto-fix during init
            const testDb = new better_sqlite3_1.default(dbPath);
            const mockDbManager = {
                getDatabase: () => testDb,
                close: () => testDb.close(),
            };
            healthCheck = new migrationHealthCheck_1.MigrationHealthCheck(mockDbManager);
            // First check what issues exist
            const beforeFix = healthCheck.runHealthCheck();
            (0, globals_1.expect)(beforeFix.issues.length).toBeGreaterThan(0);
            (0, globals_1.expect)(beforeFix.canAutoFix).toBe(true);
            // Apply auto-fix
            const success = healthCheck.runAutoFix();
            (0, globals_1.expect)(success).toBe(true);
            // Verify fixes were applied
            const afterFix = healthCheck.runHealthCheck();
            (0, globals_1.expect)(afterFix.issues.length).toBe(0);
            (0, globals_1.expect)(afterFix.summary).toContain('Database schema is healthy');
            mockDbManager.close();
        });
        (0, globals_1.it)('should handle errors gracefully when fix fails', () => {
            // Create a database with correct schema first
            dbManager = new database_1.DatabaseManager({ filename: dbPath });
            const db = dbManager.getDatabase();
            // Drop a column to simulate missing column
            db.exec(`
        CREATE TABLE temp_context_items AS SELECT id, session_id, key, value, category, priority, created_at FROM context_items;
        DROP TABLE context_items;
        ALTER TABLE temp_context_items RENAME TO context_items;
      `);
            // Create health check instance
            healthCheck = new migrationHealthCheck_1.MigrationHealthCheck(dbManager);
            const result = healthCheck.runHealthCheck();
            (0, globals_1.expect)(result.issues.length).toBeGreaterThan(0);
            // Mock exec to simulate failure
            const originalExec = db.exec.bind(db);
            db.exec = jest.fn().mockImplementation(() => {
                throw new Error('Simulated database error');
            });
            // Try to auto-fix (should fail gracefully)
            const { fixed, failed } = healthCheck.autoFixIssues(result.issues);
            (0, globals_1.expect)(fixed.length).toBe(0);
            (0, globals_1.expect)(failed.length).toBeGreaterThan(0);
            // Restore original exec
            db.exec = originalExec;
        });
    });
    (0, globals_1.describe)('Schema discovery', () => {
        (0, globals_1.it)('should correctly parse schema from database.ts file', () => {
            // Create a new database with full schema
            dbManager = new database_1.DatabaseManager({ filename: dbPath });
            healthCheck = new migrationHealthCheck_1.MigrationHealthCheck(dbManager);
            // Run health check on a properly initialized database
            const result = healthCheck.runHealthCheck();
            // Should have no issues
            (0, globals_1.expect)(result.issues.length).toBe(0);
            (0, globals_1.expect)(result.summary).toContain('Database schema is healthy');
        });
        (0, globals_1.it)('should work with empty database (new user)', () => {
            // Create completely empty database
            const db = new better_sqlite3_1.default(dbPath);
            db.close();
            // Run health check
            dbManager = new database_1.DatabaseManager({ filename: dbPath });
            healthCheck = new migrationHealthCheck_1.MigrationHealthCheck(dbManager);
            // Check should pass - tables will be created during initialization
            const result = healthCheck.runHealthCheck();
            (0, globals_1.expect)(result.summary).toContain('Database schema is healthy');
        });
    });
    (0, globals_1.describe)('Integration with DatabaseManager', () => {
        (0, globals_1.it)('should automatically fix issues on database initialization', () => {
            // Create a database with old schema
            const db = new better_sqlite3_1.default(dbPath);
            db.exec(`
        CREATE TABLE sessions (
          id TEXT PRIMARY KEY,
          name TEXT,
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        );
        
        CREATE TABLE context_items (
          id TEXT PRIMARY KEY,
          session_id TEXT NOT NULL,
          key TEXT NOT NULL,
          value TEXT NOT NULL,
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        );
      `);
            db.close();
            // Initialize DatabaseManager (should auto-fix)
            dbManager = new database_1.DatabaseManager({ filename: dbPath });
            // Verify columns were added
            const db2 = dbManager.getDatabase();
            const columns = db2.prepare('PRAGMA table_info(context_items)').all();
            const columnNames = columns.map((col) => col.name);
            (0, globals_1.expect)(columnNames).toContain('metadata');
            (0, globals_1.expect)(columnNames).toContain('size');
            (0, globals_1.expect)(columnNames).toContain('category');
            (0, globals_1.expect)(columnNames).toContain('priority');
            // Note: context_items table only has created_at, not updated_at
        });
        (0, globals_1.it)('should handle concurrent database access during migration', () => {
            // Create a database with old schema
            const db = new better_sqlite3_1.default(dbPath);
            db.exec(`
        CREATE TABLE sessions (
          id TEXT PRIMARY KEY,
          name TEXT,
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        );
      `);
            db.close();
            // Initialize multiple DatabaseManager instances concurrently
            const managers = [];
            const promises = [];
            for (let i = 0; i < 3; i++) {
                promises.push(new Promise(resolve => {
                    setTimeout(() => {
                        const manager = new database_1.DatabaseManager({ filename: dbPath });
                        managers.push(manager);
                        resolve(manager);
                    }, i * 10); // Stagger slightly
                }));
            }
            return Promise.all(promises).then(() => {
                // All should complete successfully
                (0, globals_1.expect)(managers.length).toBe(3);
                // Check that migrations were applied
                const db = managers[0].getDatabase();
                const tables = db
                    .prepare("SELECT name FROM sqlite_master WHERE type='table'")
                    .all();
                (0, globals_1.expect)(tables.length).toBeGreaterThan(10); // Should have all tables
                // Clean up
                managers.forEach(m => m.close());
            });
        });
    });
});
