"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;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const globals_1 = require("@jest/globals");
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
(0, globals_1.describe)('Server Initialization Tests', () => {
    let tempDir;
    let serverProcess = null;
    (0, globals_1.beforeEach)(() => {
        tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-test-'));
    });
    (0, globals_1.afterEach)(async () => {
        if (serverProcess && !serverProcess.killed) {
            // First try graceful shutdown
            serverProcess.kill('SIGTERM');
            // Wait for process to actually exit
            await new Promise(resolve => {
                const timeout = setTimeout(() => {
                    // Force kill if still running
                    if (serverProcess && !serverProcess.killed) {
                        serverProcess.kill('SIGKILL');
                    }
                    resolve();
                }, 5000);
                serverProcess?.on('exit', () => {
                    clearTimeout(timeout);
                    resolve();
                });
                serverProcess?.on('error', () => {
                    clearTimeout(timeout);
                    resolve();
                });
            });
            // Remove event listeners to prevent leaks
            serverProcess?.removeAllListeners();
            // Track for global cleanup
            if (global.testProcesses) {
                const index = global.testProcesses.indexOf(serverProcess);
                if (index > -1) {
                    global.testProcesses.splice(index, 1);
                }
            }
        }
        serverProcess = null;
        // Clean up temp directory
        try {
            fs.rmSync(tempDir, { recursive: true, force: true });
        }
        catch (error) {
            console.warn('Error cleaning up temp directory:', error);
        }
    });
    (0, globals_1.it)('should start server and respond to initialize request', done => {
        const dbPath = path.join(tempDir, 'test.db');
        // Start the server
        serverProcess = (0, child_process_1.spawn)('node', [path.join(__dirname, '../../../dist/index.js')], {
            env: {
                ...process.env,
                MCP_DB_PATH: dbPath,
            },
            stdio: ['pipe', 'pipe', 'pipe'],
        });
        // Track for global cleanup
        if (!global.testProcesses) {
            global.testProcesses = [];
        }
        global.testProcesses.push(serverProcess);
        // Track for global cleanup
        if (!global.testProcesses) {
            global.testProcesses = [];
        }
        global.testProcesses.push(serverProcess);
        let output = '';
        let initialized = false;
        serverProcess.stdout?.on('data', _data => {
            output += _data.toString();
            // Look for initialization response
            const lines = output.split('\n').filter(line => line.trim());
            for (const line of lines) {
                try {
                    const msg = JSON.parse(line);
                    if (msg.id === 1 && msg.result) {
                        initialized = true;
                        (0, globals_1.expect)(msg.result).toHaveProperty('protocolVersion');
                        (0, globals_1.expect)(msg.result).toHaveProperty('capabilities');
                        done();
                    }
                }
                catch (_e) {
                    // Not JSON, continue
                }
            }
        });
        serverProcess.stderr?.on('data', _data => {
            console.error('Server error:', _data.toString());
        });
        // Send initialization request
        setTimeout(() => {
            serverProcess?.stdin?.write(JSON.stringify({
                jsonrpc: '2.0',
                method: 'initialize',
                params: {
                    protocolVersion: '2024-11-05',
                    capabilities: {},
                    clientInfo: {
                        name: 'test-client',
                        version: '1.0.0',
                    },
                },
                id: 1,
            }) + '\n');
        }, 500);
        // Timeout after 5 seconds
        setTimeout(() => {
            if (!initialized) {
                done(new Error('Server did not initialize within timeout'));
            }
        }, 5000);
    });
    (0, globals_1.it)('should create database file on startup', done => {
        const dbPath = path.join(tempDir, 'context.db');
        // Change to temp directory
        const originalCwd = process.cwd();
        try {
            process.chdir(tempDir);
            // Start the server
            serverProcess = (0, child_process_1.spawn)('node', [path.join(__dirname, '../../../dist/index.js')], {
                stdio: ['pipe', 'pipe', 'pipe'],
            });
            // Track for global cleanup
            if (!global.testProcesses) {
                global.testProcesses = [];
            }
            global.testProcesses.push(serverProcess);
            // Wait for server to start
            setTimeout(() => {
                try {
                    // Check if database file was created
                    (0, globals_1.expect)(fs.existsSync(dbPath)).toBe(true);
                    // Check if it's a valid SQLite database
                    const header = fs.readFileSync(dbPath).slice(0, 16).toString();
                    (0, globals_1.expect)(header).toBe('SQLite format 3\x00');
                    process.chdir(originalCwd);
                    done();
                }
                catch (error) {
                    process.chdir(originalCwd);
                    done(error);
                }
            }, 1000);
        }
        catch (error) {
            process.chdir(originalCwd);
            done(error);
        }
    });
    (0, globals_1.it)('should handle invalid requests gracefully', done => {
        const dbPath = path.join(tempDir, 'test.db');
        serverProcess = (0, child_process_1.spawn)('node', [path.join(__dirname, '../../../dist/index.js')], {
            env: {
                ...process.env,
                MCP_DB_PATH: dbPath,
            },
            stdio: ['pipe', 'pipe', 'pipe'],
        });
        // Track for global cleanup
        if (!global.testProcesses) {
            global.testProcesses = [];
        }
        global.testProcesses.push(serverProcess);
        let output = '';
        let errorReceived = false;
        serverProcess.stdout?.on('data', _data => {
            output += _data.toString();
            const lines = output.split('\n').filter(line => line.trim());
            for (const line of lines) {
                try {
                    const msg = JSON.parse(line);
                    if (msg.id === 2 && msg.error) {
                        errorReceived = true;
                        (0, globals_1.expect)(msg.error).toHaveProperty('code');
                        (0, globals_1.expect)(msg.error).toHaveProperty('message');
                        done();
                    }
                }
                catch (_e) {
                    // Not JSON, continue
                }
            }
        });
        // Send invalid request after initialization
        setTimeout(() => {
            // Initialize first
            serverProcess?.stdin?.write(JSON.stringify({
                jsonrpc: '2.0',
                method: 'initialize',
                params: {
                    protocolVersion: '2024-11-05',
                    capabilities: {},
                },
                id: 1,
            }) + '\n');
            // Then send invalid request
            setTimeout(() => {
                serverProcess?.stdin?.write(JSON.stringify({
                    jsonrpc: '2.0',
                    method: 'tools/call',
                    params: {
                        name: 'non_existent_tool',
                        arguments: {},
                    },
                    id: 2,
                }) + '\n');
            }, 500);
        }, 500);
        // Timeout
        setTimeout(() => {
            if (!errorReceived) {
                done(new Error('Server did not return error for invalid request'));
            }
        }, 5000);
    });
    (0, globals_1.it)('should handle server shutdown gracefully', done => {
        const dbPath = path.join(tempDir, 'test.db');
        serverProcess = (0, child_process_1.spawn)('node', [path.join(__dirname, '../../../dist/index.js')], {
            env: {
                ...process.env,
                MCP_DB_PATH: dbPath,
            },
            stdio: ['pipe', 'pipe', 'pipe'],
        });
        // Track for global cleanup
        if (!global.testProcesses) {
            global.testProcesses = [];
        }
        global.testProcesses.push(serverProcess);
        let serverStarted = false;
        let timeout;
        const cleanup = () => {
            if (timeout)
                clearTimeout(timeout);
        };
        serverProcess.stdout?.on('data', _data => {
            serverStarted = true;
            // Server is ready, wait a bit then terminate
            setTimeout(() => {
                serverProcess?.kill('SIGTERM');
            }, 100);
        });
        serverProcess.stderr?.on('data', _data => {
            // Any stderr output means server is working
            serverStarted = true;
        });
        serverProcess.on('exit', code => {
            cleanup();
            (0, globals_1.expect)(serverStarted).toBe(true);
            (0, globals_1.expect)(code).toBe(null); // Killed by signal, not error
            done();
        });
        serverProcess.on('error', err => {
            cleanup();
            done(err);
        });
        // Fallback: if server doesn't start in 3 seconds, kill it anyway
        timeout = setTimeout(() => {
            if (!serverStarted) {
                serverStarted = true; // Assume it started but didn't output yet
            }
            serverProcess?.kill('SIGTERM');
        }, 3000);
    }, 15000); // Increase test timeout to 15 seconds
});
