"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const testing_1 = require("@nestjs/testing");
const typeorm_1 = require("@nestjs/typeorm");
const common_1 = require("@nestjs/common");
const ai_service_1 = require("../services/ai.service");
const ai_config_entity_1 = require("../entities/ai-config.entity");
const ai_usage_entity_1 = require("../entities/ai-usage.entity");
const openrouter_client_1 = require("../clients/openrouter.client");
describe('AIService', () => {
    let service;
    let configRepo;
    let usageRepo;
    let openRouterClient;
    const mockTenantId = '550e8400-e29b-41d4-a716-446655440001';
    const mockUserId = '550e8400-e29b-41d4-a716-446655440002';
    const mockConfig = {
        id: 'config-001',
        tenant_id: mockTenantId,
        provider: ai_config_entity_1.AIProvider.OPENROUTER,
        default_model: 'anthropic/claude-3-haiku',
        temperature: 0.7,
        max_tokens: 2048,
        is_enabled: true,
        system_prompt: 'You are a helpful assistant.',
        allow_custom_prompts: true,
        log_conversations: false,
        settings: {},
        created_at: new Date(),
        updated_at: new Date(),
    };
    const mockUsage = {
        id: 'usage-001',
        tenant_id: mockTenantId,
        user_id: mockUserId,
        provider: ai_config_entity_1.AIProvider.OPENROUTER,
        model: 'anthropic/claude-3-haiku',
        status: ai_usage_entity_1.UsageStatus.COMPLETED,
        input_tokens: 100,
        output_tokens: 50,
        cost_input: 0.000025,
        cost_output: 0.0000625,
        latency_ms: 500,
    };
    const mockChatResponse = {
        id: 'gen-001',
        model: 'anthropic/claude-3-haiku',
        choices: [
            {
                index: 0,
                message: { role: 'assistant', content: 'Hello! How can I help you?' },
                finish_reason: 'stop',
            },
        ],
        usage: {
            prompt_tokens: 100,
            completion_tokens: 50,
            total_tokens: 150,
        },
        created: Date.now(),
    };
    beforeEach(async () => {
        const mockConfigRepo = {
            findOne: jest.fn(),
            create: jest.fn(),
            save: jest.fn(),
        };
        const mockUsageRepo = {
            findOne: jest.fn(),
            create: jest.fn(),
            save: jest.fn(),
            findAndCount: jest.fn(),
            createQueryBuilder: jest.fn(),
        };
        const mockOpenRouterClient = {
            isReady: jest.fn(),
            chatCompletion: jest.fn(),
            getModels: jest.fn(),
            calculateCost: jest.fn(),
        };
        const module = await testing_1.Test.createTestingModule({
            providers: [
                ai_service_1.AIService,
                { provide: (0, typeorm_1.getRepositoryToken)(ai_config_entity_1.AIConfig), useValue: mockConfigRepo },
                { provide: (0, typeorm_1.getRepositoryToken)(ai_usage_entity_1.AIUsage), useValue: mockUsageRepo },
                { provide: openrouter_client_1.OpenRouterClient, useValue: mockOpenRouterClient },
            ],
        }).compile();
        service = module.get(ai_service_1.AIService);
        configRepo = module.get((0, typeorm_1.getRepositoryToken)(ai_config_entity_1.AIConfig));
        usageRepo = module.get((0, typeorm_1.getRepositoryToken)(ai_usage_entity_1.AIUsage));
        openRouterClient = module.get(openrouter_client_1.OpenRouterClient);
    });
    afterEach(() => {
        jest.clearAllMocks();
        jest.restoreAllMocks();
    });
    describe('getConfig', () => {
        it('should return existing config', async () => {
            configRepo.findOne.mockResolvedValue(mockConfig);
            const result = await service.getConfig(mockTenantId);
            expect(result).toEqual(mockConfig);
            expect(configRepo.findOne).toHaveBeenCalledWith({
                where: { tenant_id: mockTenantId },
            });
        });
        it('should create default config if not exists', async () => {
            configRepo.findOne.mockResolvedValue(null);
            configRepo.create.mockReturnValue(mockConfig);
            configRepo.save.mockResolvedValue(mockConfig);
            const result = await service.getConfig(mockTenantId);
            expect(result).toEqual(mockConfig);
            expect(configRepo.create).toHaveBeenCalled();
            expect(configRepo.save).toHaveBeenCalled();
        });
    });
    describe('updateConfig', () => {
        it('should update config successfully', async () => {
            configRepo.findOne.mockResolvedValue(mockConfig);
            configRepo.save.mockResolvedValue({
                ...mockConfig,
                temperature: 0.9,
                max_tokens: 4096,
            });
            const result = await service.updateConfig(mockTenantId, {
                temperature: 0.9,
                max_tokens: 4096,
            });
            expect(result.temperature).toBe(0.9);
            expect(result.max_tokens).toBe(4096);
            expect(configRepo.save).toHaveBeenCalled();
        });
        it('should update system prompt', async () => {
            configRepo.findOne.mockResolvedValue(mockConfig);
            configRepo.save.mockResolvedValue({
                ...mockConfig,
                system_prompt: 'New prompt',
            });
            const result = await service.updateConfig(mockTenantId, {
                system_prompt: 'New prompt',
            });
            expect(result.system_prompt).toBe('New prompt');
        });
        it('should disable AI features', async () => {
            configRepo.findOne.mockResolvedValue(mockConfig);
            configRepo.save.mockResolvedValue({
                ...mockConfig,
                is_enabled: false,
            });
            const result = await service.updateConfig(mockTenantId, {
                is_enabled: false,
            });
            expect(result.is_enabled).toBe(false);
        });
    });
    describe('chat', () => {
        const chatDto = {
            messages: [{ role: 'user', content: 'Hello' }],
        };
        it('should throw when AI is disabled for tenant', async () => {
            configRepo.findOne.mockResolvedValue({
                ...mockConfig,
                is_enabled: false,
            });
            await expect(service.chat(mockTenantId, mockUserId, chatDto)).rejects.toThrow(common_1.BadRequestException);
        });
        it('should throw when service not configured', async () => {
            configRepo.findOne.mockResolvedValue(mockConfig);
            openRouterClient.isReady.mockReturnValue(false);
            await expect(service.chat(mockTenantId, mockUserId, chatDto)).rejects.toThrow(common_1.BadRequestException);
        });
    });
    describe('getModels', () => {
        it('should return available models', async () => {
            const models = [
                {
                    id: 'anthropic/claude-3-haiku',
                    name: 'Claude 3 Haiku',
                    provider: 'anthropic',
                    context_length: 200000,
                    pricing: { prompt: 0.25, completion: 1.25 },
                },
            ];
            openRouterClient.getModels.mockResolvedValue(models);
            const result = await service.getModels();
            expect(result).toEqual(models);
            expect(openRouterClient.getModels).toHaveBeenCalled();
        });
    });
    describe('getCurrentMonthUsage', () => {
        it('should return usage statistics', async () => {
            const mockQueryBuilder = {
                select: jest.fn().mockReturnThis(),
                addSelect: jest.fn().mockReturnThis(),
                where: jest.fn().mockReturnThis(),
                andWhere: jest.fn().mockReturnThis(),
                getRawOne: jest.fn().mockResolvedValue({
                    request_count: '10',
                    total_input_tokens: '1000',
                    total_output_tokens: '500',
                    total_tokens: '1500',
                    total_cost: '0.05',
                    avg_latency_ms: '450',
                }),
            };
            usageRepo.createQueryBuilder.mockReturnValue(mockQueryBuilder);
            const result = await service.getCurrentMonthUsage(mockTenantId);
            expect(result.request_count).toBe(10);
            expect(result.total_input_tokens).toBe(1000);
            expect(result.total_output_tokens).toBe(500);
            expect(result.total_tokens).toBe(1500);
            expect(result.total_cost).toBe(0.05);
            expect(result.avg_latency_ms).toBe(450);
        });
        it('should return zero values for new tenant', async () => {
            const mockQueryBuilder = {
                select: jest.fn().mockReturnThis(),
                addSelect: jest.fn().mockReturnThis(),
                where: jest.fn().mockReturnThis(),
                andWhere: jest.fn().mockReturnThis(),
                getRawOne: jest.fn().mockResolvedValue({
                    request_count: '0',
                    total_input_tokens: '0',
                    total_output_tokens: '0',
                    total_tokens: '0',
                    total_cost: '0',
                    avg_latency_ms: '0',
                }),
            };
            usageRepo.createQueryBuilder.mockReturnValue(mockQueryBuilder);
            const result = await service.getCurrentMonthUsage(mockTenantId);
            expect(result.request_count).toBe(0);
            expect(result.total_cost).toBe(0);
        });
    });
    describe('getUsageHistory', () => {
        it('should return paginated usage history', async () => {
            usageRepo.findAndCount.mockResolvedValue([[mockUsage], 1]);
            const result = await service.getUsageHistory(mockTenantId, 1, 20);
            expect(result.data).toHaveLength(1);
            expect(result.total).toBe(1);
            expect(usageRepo.findAndCount).toHaveBeenCalledWith({
                where: { tenant_id: mockTenantId },
                order: { created_at: 'DESC' },
                skip: 0,
                take: 20,
            });
        });
        it('should handle pagination correctly', async () => {
            usageRepo.findAndCount.mockResolvedValue([[], 100]);
            const result = await service.getUsageHistory(mockTenantId, 5, 10);
            expect(usageRepo.findAndCount).toHaveBeenCalledWith(expect.objectContaining({
                skip: 40,
                take: 10,
            }));
            expect(result.total).toBe(100);
        });
    });
    describe('isServiceReady', () => {
        it('should return true when client is ready', () => {
            openRouterClient.isReady.mockReturnValue(true);
            expect(service.isServiceReady()).toBe(true);
        });
        it('should return false when client is not ready', () => {
            openRouterClient.isReady.mockReturnValue(false);
            expect(service.isServiceReady()).toBe(false);
        });
    });
});
//# sourceMappingURL=ai.service.spec.js.map