"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 onboarding_service_1 = require("../onboarding.service");
const tenant_entity_1 = require("../../tenants/entities/tenant.entity");
const user_entity_1 = require("../../auth/entities/user.entity");
const token_entity_1 = require("../../auth/entities/token.entity");
const subscription_entity_1 = require("../../billing/entities/subscription.entity");
const email_service_1 = require("../../email/services/email.service");
const audit_service_1 = require("../../audit/services/audit.service");
describe('OnboardingService', () => {
    let service;
    let tenantRepo;
    let userRepo;
    let tokenRepo;
    let subscriptionRepo;
    let emailService;
    let auditService;
    const mockTenantId = '550e8400-e29b-41d4-a716-446655440001';
    const mockUserId = '550e8400-e29b-41d4-a716-446655440002';
    const mockPlanId = '550e8400-e29b-41d4-a716-446655440003';
    const mockTenant = {
        id: mockTenantId,
        name: 'Test Company',
        slug: 'test-company',
        status: 'trial',
        logo_url: null,
        settings: null,
        plan_id: null,
    };
    const mockUser = {
        id: mockUserId,
        tenant_id: mockTenantId,
        email: 'test@example.com',
        first_name: 'Test',
        last_name: 'User',
        status: 'active',
    };
    const mockSubscription = {
        id: 'sub-001',
        tenant_id: mockTenantId,
        plan_id: mockPlanId,
        status: subscription_entity_1.SubscriptionStatus.ACTIVE,
    };
    beforeEach(async () => {
        const mockTenantRepo = {
            findOne: jest.fn(),
            save: jest.fn(),
        };
        const mockUserRepo = {
            findOne: jest.fn(),
            count: jest.fn(),
        };
        const mockTokenRepo = {
            count: jest.fn(),
        };
        const mockSubscriptionRepo = {
            findOne: jest.fn(),
        };
        const mockEmailService = {
            sendTemplateEmail: jest.fn(),
        };
        const mockAuditService = {
            createAuditLog: jest.fn(),
        };
        const module = await testing_1.Test.createTestingModule({
            providers: [
                onboarding_service_1.OnboardingService,
                { provide: (0, typeorm_1.getRepositoryToken)(tenant_entity_1.Tenant), useValue: mockTenantRepo },
                { provide: (0, typeorm_1.getRepositoryToken)(user_entity_1.User), useValue: mockUserRepo },
                { provide: (0, typeorm_1.getRepositoryToken)(token_entity_1.Token), useValue: mockTokenRepo },
                { provide: (0, typeorm_1.getRepositoryToken)(subscription_entity_1.Subscription), useValue: mockSubscriptionRepo },
                { provide: email_service_1.EmailService, useValue: mockEmailService },
                { provide: audit_service_1.AuditService, useValue: mockAuditService },
            ],
        }).compile();
        service = module.get(onboarding_service_1.OnboardingService);
        tenantRepo = module.get((0, typeorm_1.getRepositoryToken)(tenant_entity_1.Tenant));
        userRepo = module.get((0, typeorm_1.getRepositoryToken)(user_entity_1.User));
        tokenRepo = module.get((0, typeorm_1.getRepositoryToken)(token_entity_1.Token));
        subscriptionRepo = module.get((0, typeorm_1.getRepositoryToken)(subscription_entity_1.Subscription));
        emailService = module.get(email_service_1.EmailService);
        auditService = module.get(audit_service_1.AuditService);
    });
    afterEach(() => {
        jest.clearAllMocks();
    });
    describe('getStatus', () => {
        it('should return onboarding status for tenant with all data', async () => {
            tenantRepo.findOne.mockResolvedValue(mockTenant);
            tokenRepo.count.mockResolvedValue(3);
            userRepo.count.mockResolvedValue(2);
            subscriptionRepo.findOne.mockResolvedValue(mockSubscription);
            const result = await service.getStatus(mockTenantId);
            expect(result).toBeDefined();
            expect(result.completed).toBe(false);
            expect(result.data.company).toBeDefined();
            expect(result.data.company?.name).toBe('Test Company');
            expect(result.data.company?.slug).toBe('test-company');
            expect(result.data.team.invitesSent).toBe(3);
            expect(result.data.team.membersJoined).toBe(1);
            expect(result.data.plan.selected).toBe(true);
            expect(result.data.plan.planId).toBe(mockPlanId);
        });
        it('should return step 1 when company info is missing', async () => {
            const tenantWithoutInfo = { ...mockTenant, name: '', slug: '' };
            tenantRepo.findOne.mockResolvedValue(tenantWithoutInfo);
            tokenRepo.count.mockResolvedValue(0);
            userRepo.count.mockResolvedValue(1);
            subscriptionRepo.findOne.mockResolvedValue(null);
            const result = await service.getStatus(mockTenantId);
            expect(result.step).toBe(1);
            expect(result.data.company).toBeNull();
        });
        it('should return step 3 when plan is not selected', async () => {
            tenantRepo.findOne.mockResolvedValue(mockTenant);
            tokenRepo.count.mockResolvedValue(0);
            userRepo.count.mockResolvedValue(1);
            subscriptionRepo.findOne.mockResolvedValue(null);
            const result = await service.getStatus(mockTenantId);
            expect(result.step).toBe(3);
            expect(result.data.plan.selected).toBe(false);
        });
        it('should return step 4 when ready for completion', async () => {
            tenantRepo.findOne.mockResolvedValue(mockTenant);
            tokenRepo.count.mockResolvedValue(2);
            userRepo.count.mockResolvedValue(3);
            subscriptionRepo.findOne.mockResolvedValue(mockSubscription);
            const result = await service.getStatus(mockTenantId);
            expect(result.step).toBe(4);
        });
        it('should return completed=true when tenant is active', async () => {
            const activeTenant = { ...mockTenant, status: 'active' };
            tenantRepo.findOne.mockResolvedValue(activeTenant);
            tokenRepo.count.mockResolvedValue(0);
            userRepo.count.mockResolvedValue(1);
            subscriptionRepo.findOne.mockResolvedValue(mockSubscription);
            const result = await service.getStatus(mockTenantId);
            expect(result.completed).toBe(true);
            expect(result.step).toBe(4);
        });
        it('should throw BadRequestException when tenant not found', async () => {
            tenantRepo.findOne.mockResolvedValue(null);
            await expect(service.getStatus(mockTenantId)).rejects.toThrow(common_1.BadRequestException);
        });
    });
    describe('completeOnboarding', () => {
        it('should complete onboarding successfully', async () => {
            tenantRepo.findOne.mockResolvedValue(mockTenant);
            userRepo.findOne.mockResolvedValue(mockUser);
            tenantRepo.save.mockResolvedValue({ ...mockTenant, status: 'active' });
            auditService.createAuditLog.mockResolvedValue({});
            emailService.sendTemplateEmail.mockResolvedValue({ success: true });
            const result = await service.completeOnboarding(mockTenantId, mockUserId);
            expect(result.success).toBe(true);
            expect(result.redirectUrl).toBe('/dashboard');
            expect(tenantRepo.save).toHaveBeenCalled();
            expect(auditService.createAuditLog).toHaveBeenCalledWith(expect.objectContaining({
                tenant_id: mockTenantId,
                user_id: mockUserId,
                action: 'update',
                entity_type: 'tenant',
            }));
            expect(emailService.sendTemplateEmail).toHaveBeenCalledWith(expect.objectContaining({
                templateKey: 'welcome',
            }));
        });
        it('should return success if tenant already active', async () => {
            const activeTenant = { ...mockTenant, status: 'active' };
            tenantRepo.findOne.mockResolvedValue(activeTenant);
            const result = await service.completeOnboarding(mockTenantId, mockUserId);
            expect(result.success).toBe(true);
            expect(result.redirectUrl).toBe('/dashboard');
            expect(tenantRepo.save).not.toHaveBeenCalled();
        });
        it('should throw BadRequestException when tenant not found', async () => {
            tenantRepo.findOne.mockResolvedValue(null);
            await expect(service.completeOnboarding(mockTenantId, mockUserId)).rejects.toThrow(common_1.BadRequestException);
        });
        it('should throw BadRequestException when user not found', async () => {
            const trialTenant = { ...mockTenant, status: 'trial' };
            tenantRepo.findOne.mockResolvedValue(trialTenant);
            userRepo.findOne.mockResolvedValue(null);
            await expect(service.completeOnboarding(mockTenantId, mockUserId)).rejects.toThrow(common_1.BadRequestException);
        });
        it('should complete onboarding even if email fails', async () => {
            tenantRepo.findOne.mockResolvedValue(mockTenant);
            userRepo.findOne.mockResolvedValue(mockUser);
            tenantRepo.save.mockResolvedValue({ ...mockTenant, status: 'active' });
            auditService.createAuditLog.mockResolvedValue({});
            emailService.sendTemplateEmail.mockRejectedValue(new Error('Email failed'));
            const result = await service.completeOnboarding(mockTenantId, mockUserId);
            expect(result.success).toBe(true);
            expect(result.redirectUrl).toBe('/dashboard');
        });
        it('should update tenant status from trial to active', async () => {
            const trialTenant = { ...mockTenant, status: 'trial' };
            tenantRepo.findOne.mockResolvedValue(trialTenant);
            userRepo.findOne.mockResolvedValue(mockUser);
            tenantRepo.save.mockImplementation(async (tenant) => tenant);
            auditService.createAuditLog.mockResolvedValue({});
            emailService.sendTemplateEmail.mockResolvedValue({ success: true });
            await service.completeOnboarding(mockTenantId, mockUserId);
            expect(tenantRepo.save).toHaveBeenCalledWith(expect.objectContaining({
                status: 'active',
            }));
        });
    });
    describe('team data calculation', () => {
        it('should return 0 members joined when only owner exists', async () => {
            tenantRepo.findOne.mockResolvedValue(mockTenant);
            tokenRepo.count.mockResolvedValue(0);
            userRepo.count.mockResolvedValue(1);
            subscriptionRepo.findOne.mockResolvedValue(null);
            const result = await service.getStatus(mockTenantId);
            expect(result.data.team.membersJoined).toBe(0);
        });
        it('should count invitations correctly', async () => {
            tenantRepo.findOne.mockResolvedValue(mockTenant);
            tokenRepo.count.mockResolvedValue(5);
            userRepo.count.mockResolvedValue(1);
            subscriptionRepo.findOne.mockResolvedValue(null);
            const result = await service.getStatus(mockTenantId);
            expect(result.data.team.invitesSent).toBe(5);
        });
    });
    describe('plan data calculation', () => {
        it('should return selected=false when no subscription', async () => {
            tenantRepo.findOne.mockResolvedValue(mockTenant);
            tokenRepo.count.mockResolvedValue(0);
            userRepo.count.mockResolvedValue(1);
            subscriptionRepo.findOne.mockResolvedValue(null);
            const result = await service.getStatus(mockTenantId);
            expect(result.data.plan.selected).toBe(false);
            expect(result.data.plan.planId).toBeNull();
        });
        it('should return selected=true with planId when subscription exists', async () => {
            tenantRepo.findOne.mockResolvedValue(mockTenant);
            tokenRepo.count.mockResolvedValue(0);
            userRepo.count.mockResolvedValue(1);
            subscriptionRepo.findOne.mockResolvedValue(mockSubscription);
            const result = await service.getStatus(mockTenantId);
            expect(result.data.plan.selected).toBe(true);
            expect(result.data.plan.planId).toBe(mockPlanId);
        });
    });
});
//# sourceMappingURL=onboarding.service.spec.js.map