"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const testing_1 = require("@nestjs/testing");
const config_1 = require("@nestjs/config");
const email_service_1 = require("../services/email.service");
const mockFetch = jest.fn();
global.fetch = mockFetch;
describe('EmailService', () => {
    let service;
    let configService;
    const defaultEmailConfig = {
        provider: 'sendgrid',
        from: 'noreply@example.com',
        fromName: 'Test App',
        replyTo: 'support@example.com',
        sendgridApiKey: 'SG.test-api-key',
        sesRegion: 'us-east-1',
        sesAccessKeyId: '',
        sesSecretAccessKey: '',
        smtpHost: '',
        smtpPort: 587,
        smtpUser: '',
        smtpPassword: '',
        smtpSecure: false,
    };
    beforeEach(async () => {
        mockFetch.mockReset();
        const mockConfigService = {
            get: jest.fn().mockReturnValue(defaultEmailConfig),
        };
        const module = await testing_1.Test.createTestingModule({
            providers: [
                email_service_1.EmailService,
                { provide: config_1.ConfigService, useValue: mockConfigService },
            ],
        }).compile();
        service = module.get(email_service_1.EmailService);
        configService = module.get(config_1.ConfigService);
        service.onModuleInit();
    });
    afterEach(() => {
        jest.clearAllMocks();
    });
    describe('initialization', () => {
        it('should initialize with sendgrid provider', () => {
            expect(service.getProvider()).toBe('sendgrid');
            expect(service.isEnabled()).toBe(true);
        });
        it('should not be enabled when no API key is configured', async () => {
            configService.get.mockReturnValue({
                ...defaultEmailConfig,
                sendgridApiKey: '',
            });
            const module = await testing_1.Test.createTestingModule({
                providers: [
                    email_service_1.EmailService,
                    { provide: config_1.ConfigService, useValue: configService },
                ],
            }).compile();
            const unconfiguredService = module.get(email_service_1.EmailService);
            unconfiguredService.onModuleInit();
            expect(unconfiguredService.isEnabled()).toBe(false);
        });
    });
    describe('sendEmail', () => {
        const sendEmailDto = {
            to: { email: 'user@example.com', name: 'Test User' },
            subject: 'Test Subject',
            html: '<h1>Hello</h1>',
            text: 'Hello',
        };
        describe('SendGrid provider', () => {
            it('should send email successfully via SendGrid', async () => {
                mockFetch.mockResolvedValue({
                    ok: true,
                    headers: {
                        get: jest.fn().mockReturnValue('sg-msg-123'),
                    },
                });
                const result = await service.sendEmail(sendEmailDto);
                expect(result.success).toBe(true);
                expect(result.provider).toBe('sendgrid');
                expect(result.messageId).toBeDefined();
                expect(mockFetch).toHaveBeenCalledWith('https://api.sendgrid.com/v3/mail/send', expect.objectContaining({
                    method: 'POST',
                    headers: expect.objectContaining({
                        'Authorization': 'Bearer SG.test-api-key',
                    }),
                }));
            });
            it('should handle SendGrid API error', async () => {
                mockFetch.mockResolvedValue({
                    ok: false,
                    status: 401,
                    text: jest.fn().mockResolvedValue('Unauthorized'),
                });
                const result = await service.sendEmail(sendEmailDto);
                expect(result.success).toBe(false);
                expect(result.error).toContain('SendGrid error');
            });
            it('should include CC and BCC recipients', async () => {
                mockFetch.mockResolvedValue({
                    ok: true,
                    headers: { get: jest.fn().mockReturnValue('msg-123') },
                });
                const dtoWithCcBcc = {
                    ...sendEmailDto,
                    cc: [{ email: 'cc@example.com' }],
                    bcc: [{ email: 'bcc@example.com' }],
                };
                await service.sendEmail(dtoWithCcBcc);
                expect(mockFetch).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
                    body: expect.stringContaining('cc@example.com'),
                }));
            });
            it('should include attachments', async () => {
                mockFetch.mockResolvedValue({
                    ok: true,
                    headers: { get: jest.fn().mockReturnValue('msg-123') },
                });
                const dtoWithAttachment = {
                    ...sendEmailDto,
                    attachments: [{
                            filename: 'test.pdf',
                            content: 'base64content',
                            contentType: 'application/pdf',
                        }],
                };
                await service.sendEmail(dtoWithAttachment);
                expect(mockFetch).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
                    body: expect.stringContaining('test.pdf'),
                }));
            });
        });
        describe('when not configured', () => {
            it('should log email instead of sending', async () => {
                configService.get.mockReturnValue({
                    ...defaultEmailConfig,
                    sendgridApiKey: '',
                });
                const module = await testing_1.Test.createTestingModule({
                    providers: [
                        email_service_1.EmailService,
                        { provide: config_1.ConfigService, useValue: configService },
                    ],
                }).compile();
                const unconfiguredService = module.get(email_service_1.EmailService);
                unconfiguredService.onModuleInit();
                const result = await unconfiguredService.sendEmail(sendEmailDto);
                expect(result.success).toBe(true);
                expect(result.messageId).toMatch(/^mock-/);
                expect(mockFetch).not.toHaveBeenCalled();
            });
        });
    });
    describe('sendTemplateEmail', () => {
        it('should send email from welcome template', async () => {
            mockFetch.mockResolvedValue({
                ok: true,
                headers: { get: jest.fn().mockReturnValue('msg-123') },
            });
            const result = await service.sendTemplateEmail({
                to: { email: 'user@example.com' },
                templateKey: 'welcome',
                variables: {
                    userName: 'John',
                    appName: 'Test App',
                },
            });
            expect(result.success).toBe(true);
            expect(mockFetch).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
                body: expect.stringContaining('Welcome'),
            }));
        });
        it('should send email from password_reset template', async () => {
            mockFetch.mockResolvedValue({
                ok: true,
                headers: { get: jest.fn().mockReturnValue('msg-123') },
            });
            const result = await service.sendTemplateEmail({
                to: { email: 'user@example.com' },
                templateKey: 'password_reset',
                variables: {
                    userName: 'John',
                    resetLink: 'https://app.com/reset?token=abc',
                    expiresIn: '1 hour',
                },
            });
            expect(result.success).toBe(true);
        });
        it('should send email from invitation template', async () => {
            mockFetch.mockResolvedValue({
                ok: true,
                headers: { get: jest.fn().mockReturnValue('msg-123') },
            });
            const result = await service.sendTemplateEmail({
                to: { email: 'user@example.com' },
                templateKey: 'invitation',
                variables: {
                    inviterName: 'Admin',
                    tenantName: 'Acme Corp',
                    appName: 'Test App',
                    inviteLink: 'https://app.com/invite?code=xyz',
                    expiresIn: '7 days',
                },
            });
            expect(result.success).toBe(true);
        });
        it('should return error for unknown template', async () => {
            const result = await service.sendTemplateEmail({
                to: { email: 'user@example.com' },
                templateKey: 'unknown_template',
                variables: {},
            });
            expect(result.success).toBe(false);
            expect(result.error).toContain('Template not found');
        });
        it('should handle conditional blocks in templates', async () => {
            mockFetch.mockResolvedValue({
                ok: true,
                headers: { get: jest.fn().mockReturnValue('msg-123') },
            });
            await service.sendTemplateEmail({
                to: { email: 'user@example.com' },
                templateKey: 'notification',
                variables: {
                    title: 'New Message',
                    message: 'You have a new message',
                    actionUrl: 'https://app.com/messages',
                    actionText: 'View Message',
                },
            });
            expect(mockFetch).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
                body: expect.stringContaining('View Message'),
            }));
        });
    });
    describe('sendBulkEmails', () => {
        it('should send multiple emails in batches', async () => {
            mockFetch.mockResolvedValue({
                ok: true,
                headers: { get: jest.fn().mockReturnValue('msg-123') },
            });
            const emails = Array(15).fill(null).map((_, i) => ({
                to: { email: `user${i}@example.com` },
                subject: `Email ${i}`,
                text: `Content ${i}`,
            }));
            const results = await service.sendBulkEmails(emails);
            expect(results).toHaveLength(15);
            expect(results.every(r => r.success)).toBe(true);
            expect(mockFetch).toHaveBeenCalledTimes(15);
        });
        it('should handle partial failures in bulk send', async () => {
            mockFetch
                .mockResolvedValueOnce({ ok: true, headers: { get: () => 'msg-1' } })
                .mockResolvedValueOnce({ ok: false, status: 500, text: () => 'Error' })
                .mockResolvedValueOnce({ ok: true, headers: { get: () => 'msg-3' } });
            const emails = [
                { to: { email: 'user1@example.com' }, subject: 'Test 1', text: 'Content' },
                { to: { email: 'user2@example.com' }, subject: 'Test 2', text: 'Content' },
                { to: { email: 'user3@example.com' }, subject: 'Test 3', text: 'Content' },
            ];
            const results = await service.sendBulkEmails(emails);
            expect(results[0].success).toBe(true);
            expect(results[1].success).toBe(false);
            expect(results[2].success).toBe(true);
        });
    });
    describe('AWS SES provider', () => {
        beforeEach(async () => {
            configService.get.mockReturnValue({
                ...defaultEmailConfig,
                provider: 'ses',
                sendgridApiKey: '',
                sesAccessKeyId: 'AKIATEST',
                sesSecretAccessKey: 'secret',
            });
            const module = await testing_1.Test.createTestingModule({
                providers: [
                    email_service_1.EmailService,
                    { provide: config_1.ConfigService, useValue: configService },
                ],
            }).compile();
            service = module.get(email_service_1.EmailService);
            service.onModuleInit();
        });
        it('should use SES provider when configured', () => {
            expect(service.getProvider()).toBe('ses');
            expect(service.isEnabled()).toBe(true);
        });
    });
    describe('SMTP provider', () => {
        beforeEach(async () => {
            configService.get.mockReturnValue({
                ...defaultEmailConfig,
                provider: 'smtp',
                sendgridApiKey: '',
                smtpHost: 'smtp.example.com',
                smtpUser: 'user',
                smtpPassword: 'password',
            });
            const module = await testing_1.Test.createTestingModule({
                providers: [
                    email_service_1.EmailService,
                    { provide: config_1.ConfigService, useValue: configService },
                ],
            }).compile();
            service = module.get(email_service_1.EmailService);
            service.onModuleInit();
        });
        it('should use SMTP provider when configured', () => {
            expect(service.getProvider()).toBe('smtp');
            expect(service.isEnabled()).toBe(true);
        });
        it('should fallback to logging for SMTP (nodemailer not implemented)', async () => {
            const result = await service.sendEmail({
                to: { email: 'user@example.com' },
                subject: 'Test',
                text: 'Hello',
            });
            expect(result.success).toBe(true);
            expect(result.messageId).toMatch(/^smtp-/);
        });
    });
});
//# sourceMappingURL=email.service.spec.js.map