"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 database_1 = require("../../utils/database");
const ContextRepository_1 = require("../../repositories/ContextRepository");
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const uuid_1 = require("uuid");
(0, globals_1.describe)('Context Search Handler Integration Tests', () => {
    let dbManager;
    let tempDbPath;
    let db;
    let contextRepo;
    let testSessionId;
    (0, globals_1.beforeEach)(() => {
        tempDbPath = path.join(os.tmpdir(), `test-context-search-handler-${Date.now()}.db`);
        dbManager = new database_1.DatabaseManager({
            filename: tempDbPath,
            maxSize: 10 * 1024 * 1024,
            walMode: true,
        });
        db = dbManager.getDatabase();
        contextRepo = new ContextRepository_1.ContextRepository(dbManager);
        // Create test session
        testSessionId = (0, uuid_1.v4)();
        db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(testSessionId, 'Test Session');
    });
    (0, globals_1.afterEach)(() => {
        dbManager.close();
        try {
            fs.unlinkSync(tempDbPath);
            fs.unlinkSync(`${tempDbPath}-wal`);
            fs.unlinkSync(`${tempDbPath}-shm`);
        }
        catch (_e) {
            // Ignore
        }
    });
    (0, globals_1.describe)('Enhanced Search Method', () => {
        (0, globals_1.beforeEach)(() => {
            // Create comprehensive test data
            const now = new Date();
            const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
            const lastWeek = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
            const items = [
                {
                    id: (0, uuid_1.v4)(),
                    session_id: testSessionId,
                    key: 'auth_config',
                    value: 'Authentication configuration for the app',
                    category: 'config',
                    priority: 'high',
                    channel: 'main',
                    created_at: now.toISOString(),
                    metadata: JSON.stringify({ tags: ['auth', 'config'] }),
                    size: 40,
                },
                {
                    id: (0, uuid_1.v4)(),
                    session_id: testSessionId,
                    key: 'db_auth_connection',
                    value: 'Database connection string with auth params',
                    category: 'config',
                    priority: 'normal',
                    channel: 'feature/auth',
                    created_at: yesterday.toISOString(),
                    metadata: JSON.stringify({ tags: ['db', 'auth'] }),
                    size: 45,
                },
                {
                    id: (0, uuid_1.v4)(),
                    session_id: testSessionId,
                    key: 'user_model',
                    value: 'User model with authentication methods',
                    category: 'code',
                    priority: 'high',
                    channel: 'main',
                    created_at: lastWeek.toISOString(),
                    metadata: null,
                    size: 38,
                },
                {
                    id: (0, uuid_1.v4)(),
                    session_id: testSessionId,
                    key: 'api_endpoints',
                    value: 'API endpoints documentation',
                    category: 'docs',
                    priority: 'normal',
                    channel: 'main',
                    created_at: now.toISOString(),
                    is_private: 1,
                },
            ];
            // Insert test data
            const stmt = db.prepare(`
        INSERT INTO context_items (
          id, session_id, key, value, category, priority, channel, 
          created_at, metadata, size, is_private
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      `);
            items.forEach(item => {
                stmt.run(item.id, item.session_id, item.key, item.value, item.category || null, item.priority || 'normal', item.channel || null, item.created_at || new Date().toISOString(), item.metadata || null, item.size || Buffer.byteLength(item.value, 'utf8'), item.is_private || 0);
            });
        });
        (0, globals_1.it)('should search with basic query maintaining backward compatibility', () => {
            // Test the existing search method
            const results = contextRepo.search('auth', testSessionId, true);
            (0, globals_1.expect)(results.length).toBeGreaterThanOrEqual(3); // auth_config, db_auth_connection, user_model
            (0, globals_1.expect)(results.every(r => r.key.includes('auth') || r.value.includes('auth') || r.value.includes('Auth'))).toBe(true);
        });
        (0, globals_1.it)('should handle enhanced search with time filtering', () => {
            const twoDaysAgo = new Date();
            twoDaysAgo.setDate(twoDaysAgo.getDate() - 2);
            // Simulate enhanced search parameters
            const searchParams = {
                query: 'auth',
                sessionId: testSessionId,
                createdAfter: twoDaysAgo.toISOString(),
                searchIn: ['key', 'value'],
            };
            // Build query similar to how enhanced search would work
            let sql = `
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        AND created_at > ?
        ORDER BY priority DESC, created_at DESC
      `;
            const results = db
                .prepare(sql)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`, searchParams.createdAfter);
            (0, globals_1.expect)(results.length).toBe(2); // auth_config and db_auth_connection (not user_model which is older)
        });
        (0, globals_1.it)('should handle enhanced search with channel filtering', () => {
            const searchParams = {
                query: 'auth',
                sessionId: testSessionId,
                channel: 'feature/auth',
            };
            let sql = `
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        AND channel = ?
        ORDER BY priority DESC, created_at DESC
      `;
            const results = db
                .prepare(sql)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`, searchParams.channel);
            (0, globals_1.expect)(results.length).toBe(1);
            (0, globals_1.expect)(results[0].key).toBe('db_auth_connection');
        });
        (0, globals_1.it)('should handle enhanced search with multiple channels', () => {
            const searchParams = {
                query: 'auth',
                sessionId: testSessionId,
                channels: ['main', 'feature/auth'],
            };
            const placeholders = searchParams.channels.map(() => '?').join(',');
            let sql = `
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        AND channel IN (${placeholders})
        ORDER BY priority DESC, created_at DESC
      `;
            const results = db
                .prepare(sql)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`, ...searchParams.channels);
            (0, globals_1.expect)(results.length).toBe(3); // All items with 'auth' in main or feature/auth channels
        });
        (0, globals_1.it)('should handle sort parameter correctly', () => {
            const searchParams = {
                query: 'auth',
                sessionId: testSessionId,
                sort: 'key_asc',
            };
            let sql = `
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        ORDER BY key ASC
      `;
            const results = db
                .prepare(sql)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`);
            (0, globals_1.expect)(results[0].key).toBe('auth_config');
            (0, globals_1.expect)(results[1].key).toBe('db_auth_connection');
        });
        (0, globals_1.it)('should include metadata when requested', () => {
            const searchParams = {
                query: 'auth',
                sessionId: testSessionId,
                includeMetadata: true,
            };
            const results = db
                .prepare(`
        SELECT *, size FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        ORDER BY created_at DESC
      `)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`);
            results.forEach((item) => {
                if (searchParams.includeMetadata) {
                    // Verify metadata structure
                    if (item.metadata) {
                        const parsed = JSON.parse(item.metadata);
                        (0, globals_1.expect)(parsed).toHaveProperty('tags');
                    }
                    // Verify size is included
                    (0, globals_1.expect)(item.size).toBeGreaterThan(0);
                }
            });
        });
        (0, globals_1.it)('should handle pagination correctly', () => {
            const searchParams = {
                query: 'auth',
                sessionId: testSessionId,
                limit: 2,
                offset: 1,
            };
            // Get total count first
            const countResult = db
                .prepare(`
        SELECT COUNT(*) as count FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
      `)
                .get(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`);
            const totalCount = countResult.count;
            // Get paginated results
            const results = db
                .prepare(`
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        ORDER BY created_at DESC
        LIMIT ? OFFSET ?
      `)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`, searchParams.limit, searchParams.offset);
            (0, globals_1.expect)(results.length).toBeLessThanOrEqual(searchParams.limit);
            (0, globals_1.expect)(totalCount).toBeGreaterThanOrEqual(3);
        });
        (0, globals_1.it)('should handle keyPattern for regex-like matching', () => {
            const searchParams = {
                query: 'config', // Search in value
                sessionId: testSessionId,
                keyPattern: '*_config', // GLOB pattern for keys ending with _config
            };
            let sql = `
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        AND key GLOB ?
        ORDER BY created_at DESC
      `;
            const results = db
                .prepare(sql)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`, searchParams.keyPattern);
            (0, globals_1.expect)(results.length).toBe(1);
            (0, globals_1.expect)(results[0].key).toBe('auth_config');
        });
        (0, globals_1.it)('should filter by priorities', () => {
            const searchParams = {
                query: 'auth',
                sessionId: testSessionId,
                priorities: ['high'],
            };
            const placeholders = searchParams.priorities.map(() => '?').join(',');
            let sql = `
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        AND priority IN (${placeholders})
        ORDER BY created_at DESC
      `;
            const results = db
                .prepare(sql)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`, ...searchParams.priorities);
            (0, globals_1.expect)(results.length).toBe(2); // auth_config and user_model
            (0, globals_1.expect)(results.every((r) => r.priority === 'high')).toBe(true);
        });
        (0, globals_1.it)('should respect privacy settings', () => {
            // Search without session (should not see private items)
            const publicResults = db
                .prepare(`
        SELECT * FROM context_items 
        WHERE is_private = 0
        ORDER BY created_at DESC
      `)
                .all();
            (0, globals_1.expect)(publicResults.some((r) => r.key === 'api_endpoints')).toBe(false);
            // Search with session (should see own private items)
            const sessionResults = db
                .prepare(`
        SELECT * FROM context_items 
        WHERE (is_private = 0 OR session_id = ?)
        ORDER BY created_at DESC
      `)
                .all(testSessionId);
            (0, globals_1.expect)(sessionResults.some((r) => r.key === 'api_endpoints')).toBe(true);
        });
        (0, globals_1.it)('should handle relative time parsing', () => {
            // Add a recent item
            const oneHourAgo = new Date();
            oneHourAgo.setHours(oneHourAgo.getHours() - 1);
            db.prepare('INSERT INTO context_items (id, session_id, key, value, created_at) VALUES (?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), testSessionId, 'recent_auth_task', 'Recent authentication task', oneHourAgo.toISOString());
            // Simulate relative time parsing
            const relativeTime = '2 hours ago';
            const match = relativeTime.match(/^(\d+) hours? ago$/);
            (0, globals_1.expect)(match).toBeTruthy();
            const hours = parseInt(match[1]);
            const cutoffTime = new Date();
            cutoffTime.setHours(cutoffTime.getHours() - hours);
            const results = db
                .prepare(`
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        AND created_at > ?
        ORDER BY created_at DESC
      `)
                .all(testSessionId, '%auth%', '%auth%', cutoffTime.toISOString());
            (0, globals_1.expect)(results.some((r) => r.key === 'recent_auth_task')).toBe(true);
            (0, globals_1.expect)(results.some((r) => r.key === 'auth_config')).toBe(true);
        });
        (0, globals_1.it)('should handle complex combined filters', () => {
            const now = new Date();
            const twoDaysAgo = new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000);
            const searchParams = {
                query: 'auth',
                sessionId: testSessionId,
                channels: ['main', 'feature/auth'],
                priorities: ['high', 'normal'],
                createdAfter: twoDaysAgo.toISOString(),
                sort: 'created_at_desc',
                limit: 10,
                includeMetadata: true,
            };
            // Build complex query
            const channelPlaceholders = searchParams.channels.map(() => '?').join(',');
            const priorityPlaceholders = searchParams.priorities.map(() => '?').join(',');
            let sql = `
        SELECT *, size FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        AND channel IN (${channelPlaceholders})
        AND priority IN (${priorityPlaceholders})
        AND created_at > ?
        ORDER BY created_at DESC
        LIMIT ?
      `;
            const results = db
                .prepare(sql)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`, ...searchParams.channels, ...searchParams.priorities, searchParams.createdAfter, searchParams.limit);
            // Should get auth_config and db_auth_connection (not user_model which is older)
            (0, globals_1.expect)(results.length).toBe(2);
            (0, globals_1.expect)(results[0].key).toBe('auth_config'); // Most recent
            (0, globals_1.expect)(results[1].key).toBe('db_auth_connection');
        });
    });
    (0, globals_1.describe)('searchIn Parameter Handling', () => {
        (0, globals_1.beforeEach)(() => {
            // Add specific test data
            db.prepare('INSERT INTO context_items (id, session_id, key, value) VALUES (?, ?, ?, ?)').run((0, uuid_1.v4)(), testSessionId, 'authentication_service', 'Service for user login');
            db.prepare('INSERT INTO context_items (id, session_id, key, value) VALUES (?, ?, ?, ?)').run((0, uuid_1.v4)(), testSessionId, 'user_service', 'Service for authentication');
        });
        (0, globals_1.it)('should search in both key and value when searchIn includes both', () => {
            const searchParams = {
                query: 'authentication',
                sessionId: testSessionId,
                searchIn: ['key', 'value'],
            };
            const results = db
                .prepare(`
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND (key LIKE ? OR value LIKE ?)
        ORDER BY created_at DESC
      `)
                .all(searchParams.sessionId, `%${searchParams.query}%`, `%${searchParams.query}%`);
            (0, globals_1.expect)(results.length).toBe(2);
        });
        (0, globals_1.it)('should search only in keys when searchIn is ["key"]', () => {
            const searchParams = {
                query: 'authentication',
                sessionId: testSessionId,
                searchIn: ['key'],
            };
            const results = db
                .prepare(`
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND key LIKE ?
        ORDER BY created_at DESC
      `)
                .all(searchParams.sessionId, `%${searchParams.query}%`);
            (0, globals_1.expect)(results.length).toBe(1);
            (0, globals_1.expect)(results[0].key).toBe('authentication_service');
        });
        (0, globals_1.it)('should search only in values when searchIn is ["value"]', () => {
            const searchParams = {
                query: 'authentication',
                sessionId: testSessionId,
                searchIn: ['value'],
            };
            const results = db
                .prepare(`
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND value LIKE ?
        ORDER BY created_at DESC
      `)
                .all(searchParams.sessionId, `%${searchParams.query}%`);
            (0, globals_1.expect)(results.length).toBe(1);
            (0, globals_1.expect)(results[0].key).toBe('user_service');
        });
    });
    (0, globals_1.describe)('Response Format', () => {
        (0, globals_1.beforeEach)(() => {
            // Add test data
            for (let i = 0; i < 5; i++) {
                db.prepare('INSERT INTO context_items (id, session_id, key, value, priority, size) VALUES (?, ?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), testSessionId, `test_item_${i}`, `Test value containing auth keyword ${i}`, i % 2 === 0 ? 'high' : 'normal', 50 + i * 10);
            }
        });
        (0, globals_1.it)('should format response without metadata', () => {
            const results = db
                .prepare(`
        SELECT * FROM context_items 
        WHERE session_id = ?
        AND value LIKE ?
        ORDER BY created_at DESC
      `)
                .all(testSessionId, '%auth%');
            // Simulate handler response formatting
            const formatted = results.map((r) => ({
                key: r.key,
                value: r.value,
                category: r.category,
                priority: r.priority,
            }));
            (0, globals_1.expect)(formatted.length).toBe(5);
            formatted.forEach((item) => {
                (0, globals_1.expect)(item).toHaveProperty('key');
                (0, globals_1.expect)(item).toHaveProperty('value');
                (0, globals_1.expect)(item).toHaveProperty('priority');
                (0, globals_1.expect)(item).not.toHaveProperty('size');
                (0, globals_1.expect)(item).not.toHaveProperty('created_at');
            });
        });
        (0, globals_1.it)('should format response with metadata when requested', () => {
            const results = db
                .prepare(`
        SELECT *, size FROM context_items 
        WHERE session_id = ?
        AND value LIKE ?
        ORDER BY created_at DESC
        LIMIT 3
      `)
                .all(testSessionId, '%auth%');
            // Get total count
            const countResult = db
                .prepare(`
        SELECT COUNT(*) as count FROM context_items 
        WHERE session_id = ?
        AND value LIKE ?
      `)
                .get(testSessionId, '%auth%');
            // Simulate handler response with metadata
            const formattedWithMetadata = {
                items: results.map((item) => ({
                    key: item.key,
                    value: item.value,
                    category: item.category,
                    priority: item.priority,
                    channel: item.channel,
                    metadata: item.metadata ? JSON.parse(item.metadata) : null,
                    size: item.size,
                    created_at: item.created_at,
                    updated_at: item.updated_at,
                })),
                totalCount: countResult.count,
                page: 1,
                pageSize: 3,
            };
            (0, globals_1.expect)(formattedWithMetadata.items.length).toBe(3);
            (0, globals_1.expect)(formattedWithMetadata.totalCount).toBe(5);
            (0, globals_1.expect)(formattedWithMetadata.page).toBe(1);
            (0, globals_1.expect)(formattedWithMetadata.pageSize).toBe(3);
            formattedWithMetadata.items.forEach((item) => {
                (0, globals_1.expect)(item).toHaveProperty('size');
                (0, globals_1.expect)(item).toHaveProperty('created_at');
                (0, globals_1.expect)(item).toHaveProperty('updated_at');
            });
        });
    });
    (0, globals_1.describe)('Error Handling', () => {
        (0, globals_1.it)('should handle empty search query gracefully', () => {
            const results = contextRepo.search('', testSessionId, true);
            (0, globals_1.expect)(results.length).toBe(0);
        });
        (0, globals_1.it)('should handle non-existent session gracefully', () => {
            const results = contextRepo.search('test', 'non-existent-session', true);
            (0, globals_1.expect)(results.length).toBe(0);
        });
        (0, globals_1.it)('should handle SQL injection attempts safely', () => {
            const maliciousQuery = "'; DROP TABLE context_items; --";
            // This should not throw and should not damage the database
            const _results = contextRepo.search(maliciousQuery, testSessionId, true);
            // Verify table still exists
            const tableExists = db
                .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='context_items'")
                .get();
            (0, globals_1.expect)(tableExists).toBeTruthy();
        });
    });
});
