"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");
// Removed unused import: ValidationError
(0, globals_1.describe)('Pagination Defaults Handler Integration Tests', () => {
    let dbManager;
    let tempDbPath;
    let db;
    let contextRepo;
    let testSessionId;
    (0, globals_1.beforeEach)(() => {
        tempDbPath = path.join(os.tmpdir(), `test-pagination-defaults-${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)('Default Pagination Parameters', () => {
        (0, globals_1.beforeEach)(() => {
            // Create 150 test items to test pagination limits
            const now = new Date();
            for (let i = 0; i < 150; i++) {
                const createdAt = new Date(now.getTime() - i * 60 * 1000); // 1 minute apart
                db.prepare(`
          INSERT INTO context_items (id, session_id, key, value, created_at, priority, size)
          VALUES (?, ?, ?, ?, ?, ?, ?)
        `).run((0, uuid_1.v4)(), testSessionId, `test.item.${i.toString().padStart(3, '0')}`, `Test value ${i} - ${`This is a longer test value to simulate real content that might contain various information and details that would typically be stored in a context item.`.repeat(3)}`, createdAt.toISOString(), i % 3 === 0 ? 'high' : i % 3 === 1 ? 'normal' : 'low', 500 + i * 10 // Varying sizes
                );
            }
        });
        (0, globals_1.it)('should apply default limit of 100 when not specified', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
            });
            (0, globals_1.expect)(result.items.length).toBe(100);
            (0, globals_1.expect)(result.totalCount).toBe(150);
        });
        (0, globals_1.it)('should apply default sort of created_desc when not specified', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
            });
            // Verify items are sorted by created_at descending (newest first)
            for (let i = 1; i < result.items.length; i++) {
                const prevDate = new Date(result.items[i - 1].created_at);
                const currDate = new Date(result.items[i].created_at);
                (0, globals_1.expect)(prevDate.getTime()).toBeGreaterThanOrEqual(currDate.getTime());
            }
            // First item should be the most recent (test.item.000)
            (0, globals_1.expect)(result.items[0].key).toBe('test.item.000');
        });
        (0, globals_1.it)('should respect explicit limit over default', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                limit: 50,
            });
            (0, globals_1.expect)(result.items.length).toBe(50);
            (0, globals_1.expect)(result.totalCount).toBe(150);
        });
        (0, globals_1.it)('should respect explicit sort over default', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                sort: 'key_asc',
            });
            // Verify items are sorted by key ascending
            for (let i = 1; i < result.items.length; i++) {
                (0, globals_1.expect)(result.items[i - 1].key.localeCompare(result.items[i].key)).toBeLessThanOrEqual(0);
            }
            // First item should be test.item.000 (lexicographically first)
            (0, globals_1.expect)(result.items[0].key).toBe('test.item.000');
        });
        (0, globals_1.it)('should handle limit of 0 as unlimited', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                limit: 0,
            });
            (0, globals_1.expect)(result.items.length).toBe(150); // All items
            (0, globals_1.expect)(result.totalCount).toBe(150);
        });
        (0, globals_1.it)('should handle negative limit as default', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                limit: -1,
            });
            (0, globals_1.expect)(result.items.length).toBe(100); // Default limit
            (0, globals_1.expect)(result.totalCount).toBe(150);
        });
    });
    (0, globals_1.describe)('Token Limit Safety', () => {
        (0, globals_1.beforeEach)(() => {
            // Create items with varying sizes to test token safety
            const largeValue = 'A'.repeat(5000); // 5KB per item
            for (let i = 0; i < 50; i++) {
                db.prepare(`
          INSERT INTO context_items (id, session_id, key, value, size, created_at)
          VALUES (?, ?, ?, ?, ?, ?)
        `).run((0, uuid_1.v4)(), testSessionId, `large.item.${i}`, largeValue, 5000, new Date(Date.now() - i * 1000).toISOString());
            }
        });
        (0, globals_1.it)('should calculate approximate token usage in response', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                includeMetadata: true,
            });
            // Calculate approximate token usage
            let totalSize = 0;
            result.items.forEach(item => {
                totalSize += item.size || Buffer.byteLength(item.value, 'utf8');
            });
            // With metadata, response should include size information
            (0, globals_1.expect)(result.items.every(item => item.size !== undefined)).toBe(true);
            // Verify we don't exceed safe limits
            // Rough estimate: 1 token ≈ 4 characters
            const estimatedTokens = totalSize / 4;
            const safeTokenLimit = 100000; // Conservative limit
            (0, globals_1.expect)(estimatedTokens).toBeLessThan(safeTokenLimit);
        });
        (0, globals_1.it)('should provide size summary when includeMetadata is true', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                includeMetadata: true,
                limit: 10,
            });
            // Calculate total size of returned items
            const totalSize = result.items.reduce((sum, item) => sum + (item.size || 0), 0);
            // Handler should include this information
            const handlerResponse = {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            items: result.items,
                            pagination: {
                                totalCount: result.totalCount,
                                returnedCount: result.items.length,
                                totalSize: totalSize,
                                averageSize: Math.round(totalSize / result.items.length),
                            },
                        }, null, 2),
                    },
                ],
            };
            const parsed = JSON.parse(handlerResponse.content[0].text);
            (0, globals_1.expect)(parsed.pagination.totalSize).toBe(totalSize);
            (0, globals_1.expect)(parsed.pagination.averageSize).toBeGreaterThan(0);
        });
        (0, globals_1.it)('should warn when approaching token limits', () => {
            // Create a scenario where default pagination would exceed safe limits
            const hugeValue = 'B'.repeat(10000); // 10KB per item
            for (let i = 0; i < 200; i++) {
                db.prepare(`
          INSERT INTO context_items (id, session_id, key, value, size, created_at)
          VALUES (?, ?, ?, ?, ?, ?)
        `).run((0, uuid_1.v4)(), testSessionId, `huge.item.${i}`, hugeValue, 10000, new Date(Date.now() - i * 1000).toISOString());
            }
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                includeMetadata: true,
            });
            // Should still respect the 100 item limit
            (0, globals_1.expect)(result.items.length).toBe(100);
            // Calculate if this would be safe
            const totalSize = result.items.reduce((sum, item) => sum + (item.size || 0), 0);
            const estimatedTokens = totalSize / 4;
            // Handler could include a warning if needed
            if (estimatedTokens > 50000) {
                const handlerResponse = {
                    content: [
                        {
                            type: 'text',
                            text: JSON.stringify({
                                items: result.items,
                                pagination: {
                                    totalCount: result.totalCount,
                                    returnedCount: result.items.length,
                                    warning: 'Large result set. Consider using smaller limit or more specific filters.',
                                },
                            }, null, 2),
                        },
                    ],
                };
                const parsed = JSON.parse(handlerResponse.content[0].text);
                (0, globals_1.expect)(parsed.pagination.warning).toBeTruthy();
            }
        });
    });
    (0, globals_1.describe)('Pagination Metadata in Response', () => {
        (0, globals_1.beforeEach)(() => {
            // Create 25 items for easier pagination testing
            for (let i = 0; i < 25; i++) {
                db.prepare(`
          INSERT INTO context_items (id, session_id, key, value, created_at)
          VALUES (?, ?, ?, ?, ?)
        `).run((0, uuid_1.v4)(), testSessionId, `page.item.${i.toString().padStart(2, '0')}`, `Value ${i}`, new Date(Date.now() - i * 60000).toISOString());
            }
        });
        (0, globals_1.it)('should include complete pagination metadata', () => {
            const limit = 10;
            const offset = 10;
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                limit: limit,
                offset: offset,
            });
            // Calculate pagination metadata
            const currentPage = Math.floor(offset / limit) + 1;
            const totalPages = Math.ceil(result.totalCount / limit);
            const hasNextPage = currentPage < totalPages;
            const hasPreviousPage = currentPage > 1;
            // Simulate handler response with full pagination metadata
            const handlerResponse = {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            items: result.items.map(item => ({
                                key: item.key,
                                value: item.value,
                                category: item.category,
                                priority: item.priority,
                            })),
                            pagination: {
                                totalCount: result.totalCount,
                                page: currentPage,
                                pageSize: limit,
                                totalPages: totalPages,
                                hasNextPage: hasNextPage,
                                hasPreviousPage: hasPreviousPage,
                                nextOffset: hasNextPage ? offset + limit : null,
                                previousOffset: hasPreviousPage ? Math.max(0, offset - limit) : null,
                            },
                        }, null, 2),
                    },
                ],
            };
            const parsed = JSON.parse(handlerResponse.content[0].text);
            (0, globals_1.expect)(parsed.pagination.totalCount).toBe(25);
            (0, globals_1.expect)(parsed.pagination.page).toBe(2);
            (0, globals_1.expect)(parsed.pagination.pageSize).toBe(10);
            (0, globals_1.expect)(parsed.pagination.totalPages).toBe(3);
            (0, globals_1.expect)(parsed.pagination.hasNextPage).toBe(true);
            (0, globals_1.expect)(parsed.pagination.hasPreviousPage).toBe(true);
            (0, globals_1.expect)(parsed.pagination.nextOffset).toBe(20);
            (0, globals_1.expect)(parsed.pagination.previousOffset).toBe(0);
        });
        (0, globals_1.it)('should handle first page correctly', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                limit: 10,
                offset: 0,
            });
            const handlerResponse = {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            items: result.items,
                            pagination: {
                                totalCount: result.totalCount,
                                page: 1,
                                pageSize: 10,
                                totalPages: 3,
                                hasNextPage: true,
                                hasPreviousPage: false,
                                nextOffset: 10,
                                previousOffset: null,
                            },
                        }, null, 2),
                    },
                ],
            };
            const parsed = JSON.parse(handlerResponse.content[0].text);
            (0, globals_1.expect)(parsed.pagination.page).toBe(1);
            (0, globals_1.expect)(parsed.pagination.hasPreviousPage).toBe(false);
            (0, globals_1.expect)(parsed.pagination.hasNextPage).toBe(true);
        });
        (0, globals_1.it)('should handle last page correctly', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                limit: 10,
                offset: 20,
            });
            const handlerResponse = {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            items: result.items,
                            pagination: {
                                totalCount: result.totalCount,
                                page: 3,
                                pageSize: 10,
                                totalPages: 3,
                                hasNextPage: false,
                                hasPreviousPage: true,
                                nextOffset: null,
                                previousOffset: 10,
                            },
                        }, null, 2),
                    },
                ],
            };
            const parsed = JSON.parse(handlerResponse.content[0].text);
            (0, globals_1.expect)(parsed.pagination.page).toBe(3);
            (0, globals_1.expect)(parsed.pagination.hasNextPage).toBe(false);
            (0, globals_1.expect)(parsed.pagination.hasPreviousPage).toBe(true);
            (0, globals_1.expect)(parsed.items.length).toBe(5); // Only 5 items on last page
        });
        (0, globals_1.it)('should handle single page results', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                limit: 50, // More than total items
            });
            const handlerResponse = {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            items: result.items,
                            pagination: {
                                totalCount: result.totalCount,
                                page: 1,
                                pageSize: 50,
                                totalPages: 1,
                                hasNextPage: false,
                                hasPreviousPage: false,
                                nextOffset: null,
                                previousOffset: null,
                            },
                        }, null, 2),
                    },
                ],
            };
            const parsed = JSON.parse(handlerResponse.content[0].text);
            (0, globals_1.expect)(parsed.pagination.totalPages).toBe(1);
            (0, globals_1.expect)(parsed.pagination.hasNextPage).toBe(false);
            (0, globals_1.expect)(parsed.pagination.hasPreviousPage).toBe(false);
        });
    });
    (0, globals_1.describe)('Default Behavior with Filters', () => {
        (0, globals_1.beforeEach)(() => {
            const categories = ['task', 'decision', 'progress', 'note'];
            const priorities = ['high', 'normal', 'low'];
            const channels = ['main', 'feature', 'bugfix'];
            for (let i = 0; i < 120; i++) {
                db.prepare(`
          INSERT INTO context_items (
            id, session_id, key, value, category, priority, channel, created_at
          ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        `).run((0, uuid_1.v4)(), testSessionId, `filtered.item.${i}`, `Filtered value ${i}`, categories[i % categories.length], priorities[i % priorities.length], channels[i % channels.length], new Date(Date.now() - i * 60000).toISOString());
            }
        });
        (0, globals_1.it)('should apply defaults with category filter', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                category: 'task',
            });
            // Should still apply default limit
            (0, globals_1.expect)(result.items.length).toBeLessThanOrEqual(100);
            (0, globals_1.expect)(result.items.every(item => item.category === 'task')).toBe(true);
            // Should still apply default sort
            for (let i = 1; i < result.items.length; i++) {
                const prevDate = new Date(result.items[i - 1].created_at);
                const currDate = new Date(result.items[i].created_at);
                (0, globals_1.expect)(prevDate.getTime()).toBeGreaterThanOrEqual(currDate.getTime());
            }
        });
        (0, globals_1.it)('should apply defaults with multiple filters', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                category: 'task', // Only single category is supported
                priorities: ['high'],
                channels: ['main', 'feature'],
            });
            // Should apply all filters
            (0, globals_1.expect)(result.items.every(item => item.category === 'task' &&
                item.priority === 'high' &&
                (item.channel === 'main' || item.channel === 'feature'))).toBe(true);
            // Should still apply default limit (even if fewer items match)
            (0, globals_1.expect)(result.items.length).toBeLessThanOrEqual(100);
            // Should still apply default sort
            for (let i = 1; i < result.items.length; i++) {
                const prevDate = new Date(result.items[i - 1].created_at);
                const currDate = new Date(result.items[i].created_at);
                (0, globals_1.expect)(prevDate.getTime()).toBeGreaterThanOrEqual(currDate.getTime());
            }
        });
        (0, globals_1.it)('should apply defaults with search pattern', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                keyPattern: 'filtered.item.1*',
            });
            // Should match items like filtered.item.1, filtered.item.10-19, filtered.item.100-119
            (0, globals_1.expect)(result.items.every(item => item.key.match(/^filtered\.item\.1/))).toBe(true);
            // Should still apply defaults
            (0, globals_1.expect)(result.items.length).toBeLessThanOrEqual(100);
        });
    });
    (0, globals_1.describe)('Handler Response Format with Defaults', () => {
        (0, globals_1.beforeEach)(() => {
            for (let i = 0; i < 10; i++) {
                db.prepare(`
          INSERT INTO context_items (id, session_id, key, value, created_at)
          VALUES (?, ?, ?, ?, ?)
        `).run((0, uuid_1.v4)(), testSessionId, `response.item.${i}`, `Response value ${i}`, new Date(Date.now() - i * 60000).toISOString());
            }
        });
        (0, globals_1.it)('should indicate when defaults were applied', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
            });
            // Handler could include information about applied defaults
            const handlerResponse = {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            items: result.items.map(item => ({
                                key: item.key,
                                value: item.value,
                                category: item.category,
                                priority: item.priority,
                            })),
                            pagination: {
                                totalCount: result.totalCount,
                                limit: 100,
                                offset: 0,
                                defaultsApplied: {
                                    limit: true,
                                    sort: true,
                                },
                            },
                        }, null, 2),
                    },
                ],
            };
            const parsed = JSON.parse(handlerResponse.content[0].text);
            (0, globals_1.expect)(parsed.pagination.defaultsApplied.limit).toBe(true);
            (0, globals_1.expect)(parsed.pagination.defaultsApplied.sort).toBe(true);
        });
        (0, globals_1.it)('should not indicate defaults when explicit values provided', () => {
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                limit: 5,
                sort: 'key_asc',
            });
            const handlerResponse = {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            items: result.items,
                            pagination: {
                                totalCount: result.totalCount,
                                limit: 5,
                                offset: 0,
                                defaultsApplied: {
                                    limit: false,
                                    sort: false,
                                },
                            },
                        }, null, 2),
                    },
                ],
            };
            const parsed = JSON.parse(handlerResponse.content[0].text);
            (0, globals_1.expect)(parsed.pagination.defaultsApplied.limit).toBe(false);
            (0, globals_1.expect)(parsed.pagination.defaultsApplied.sort).toBe(false);
        });
    });
    (0, globals_1.describe)('Error Handling', () => {
        (0, globals_1.it)('should handle invalid pagination parameters gracefully', () => {
            // Test with invalid limit type
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                limit: 'invalid',
            });
            // Should fall back to default
            (0, globals_1.expect)(result.items.length).toBeLessThanOrEqual(100);
        });
        (0, globals_1.it)('should handle offset beyond available items', () => {
            // Create only 5 items
            for (let i = 0; i < 5; i++) {
                db.prepare(`
          INSERT INTO context_items (id, session_id, key, value)
          VALUES (?, ?, ?, ?)
        `).run((0, uuid_1.v4)(), testSessionId, `limited.${i}`, `Value ${i}`);
            }
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
                offset: 100, // Way beyond available items
            });
            (0, globals_1.expect)(result.items.length).toBe(0);
            (0, globals_1.expect)(result.totalCount).toBe(5);
            // Handler should handle this gracefully
            const handlerResponse = {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            items: [],
                            pagination: {
                                totalCount: 5,
                                page: 11, // offset 100 / limit 10 + 1
                                pageSize: 10,
                                totalPages: 1,
                                hasNextPage: false,
                                hasPreviousPage: true,
                                message: 'No items found at this offset',
                            },
                        }, null, 2),
                    },
                ],
            };
            const parsed = JSON.parse(handlerResponse.content[0].text);
            (0, globals_1.expect)(parsed.items).toEqual([]);
            (0, globals_1.expect)(parsed.pagination.message).toBeTruthy();
        });
    });
    (0, globals_1.describe)('Performance with Default Pagination', () => {
        (0, globals_1.it)('should handle large datasets efficiently with defaults', () => {
            // Create 1000 items
            const stmt = db.prepare(`
        INSERT INTO context_items (id, session_id, key, value, created_at)
        VALUES (?, ?, ?, ?, ?)
      `);
            for (let i = 0; i < 1000; i++) {
                stmt.run((0, uuid_1.v4)(), testSessionId, `perf.item.${i.toString().padStart(4, '0')}`, `Performance test value ${i}`, new Date(Date.now() - i * 1000).toISOString());
            }
            const startTime = Date.now();
            const result = contextRepo.queryEnhanced({
                sessionId: testSessionId,
            });
            const endTime = Date.now();
            // Should complete quickly even with 1000 items
            (0, globals_1.expect)(endTime - startTime).toBeLessThan(100);
            // Should return only default limit
            (0, globals_1.expect)(result.items.length).toBe(100);
            (0, globals_1.expect)(result.totalCount).toBe(1000);
            // First 100 items should be the most recent
            (0, globals_1.expect)(result.items[0].key).toBe('perf.item.0000');
            (0, globals_1.expect)(result.items[99].key).toBe('perf.item.0099');
        });
    });
});
