/**
 * Onboarding analytics tests — step tracking, completion, funnel.
 */

import { describe, it, expect, beforeAll } from 'vitest';
import * as repo from './repository.js';
import {
  TrackStepSchema,
  TrackCompletionSchema,
  type OnboardingEventDoc,
  type OnboardingCompletionDoc,
} from './types.js';

const PRODUCT = 'onboard-test-product';

describe('onboarding analytics', () => {
  beforeAll(async () => {
    // Seed step events for 3 users across 3 steps
    const steps: OnboardingEventDoc[] = [
      {
        id: 'obs_1',
        productId: PRODUCT,
        userId: 'user-a',
        stepName: 'welcome',
        stepIndex: 0,
        completedAt: '2026-03-19T10:00:00.000Z',
      },
      {
        id: 'obs_2',
        productId: PRODUCT,
        userId: 'user-a',
        stepName: 'profile',
        stepIndex: 1,
        completedAt: '2026-03-19T10:01:00.000Z',
      },
      {
        id: 'obs_3',
        productId: PRODUCT,
        userId: 'user-a',
        stepName: 'first_action',
        stepIndex: 2,
        completedAt: '2026-03-19T10:02:00.000Z',
      },
      {
        id: 'obs_4',
        productId: PRODUCT,
        userId: 'user-b',
        stepName: 'welcome',
        stepIndex: 0,
        completedAt: '2026-03-19T10:00:00.000Z',
      },
      {
        id: 'obs_5',
        productId: PRODUCT,
        userId: 'user-b',
        stepName: 'profile',
        stepIndex: 1,
        completedAt: '2026-03-19T10:01:00.000Z',
      },
      {
        id: 'obs_6',
        productId: PRODUCT,
        userId: 'user-c',
        stepName: 'welcome',
        stepIndex: 0,
        completedAt: '2026-03-19T10:00:00.000Z',
      },
    ];
    for (const s of steps) {
      await repo.trackStep(s);
    }

    // Seed completions for user-a only
    const completion: OnboardingCompletionDoc = {
      id: 'obc_1',
      productId: PRODUCT,
      userId: 'user-a',
      completedAt: '2026-03-19T10:03:00.000Z',
      totalSteps: 3,
      durationMs: 180000,
    };
    await repo.trackCompletion(completion);
  });

  it('TrackStepSchema validates required fields', () => {
    const valid = TrackStepSchema.safeParse({
      userId: 'user-1',
      stepName: 'welcome',
      stepIndex: 0,
    });
    expect(valid.success).toBe(true);

    const invalid = TrackStepSchema.safeParse({
      userId: '',
      stepName: 'welcome',
      stepIndex: 0,
    });
    expect(invalid.success).toBe(false);
  });

  it('TrackCompletionSchema has correct defaults', () => {
    const parsed = TrackCompletionSchema.parse({ userId: 'user-1' });
    expect(parsed.totalSteps).toBe(1);
    expect(parsed.durationMs).toBeUndefined();
  });

  it('getFunnel returns correct funnel data', async () => {
    const funnel = await repo.getFunnel(PRODUCT);

    expect(funnel.productId).toBe(PRODUCT);
    expect(funnel.totalStarted).toBe(3); // 3 unique users
    expect(funnel.totalCompleted).toBe(1); // only user-a completed
    expect(funnel.completionRate).toBeCloseTo(1 / 3, 2);
    expect(funnel.avgDurationMs).toBe(180000);

    // Steps sorted by stepIndex
    expect(funnel.steps.length).toBe(3);
    expect(funnel.steps[0].stepName).toBe('welcome');
    expect(funnel.steps[0].uniqueUsers).toBe(3);
    expect(funnel.steps[0].conversionRate).toBe(1.0);

    expect(funnel.steps[1].stepName).toBe('profile');
    expect(funnel.steps[1].uniqueUsers).toBe(2);
    expect(funnel.steps[1].conversionRate).toBeCloseTo(2 / 3, 2);

    expect(funnel.steps[2].stepName).toBe('first_action');
    expect(funnel.steps[2].uniqueUsers).toBe(1);
    expect(funnel.steps[2].conversionRate).toBeCloseTo(1 / 3, 2);
  });

  it('getFunnel with date filter narrows results', async () => {
    const funnel = await repo.getFunnel(
      PRODUCT,
      '2026-03-19T10:01:00.000Z',
      '2026-03-19T10:02:00.000Z'
    );

    // Only steps within that window
    expect(funnel.totalStarted).toBeGreaterThanOrEqual(1);
  });

  it('getUserSteps returns steps for a specific user', async () => {
    const steps = await repo.getUserSteps(PRODUCT, 'user-a');

    expect(steps.length).toBe(3);
    expect(steps[0].stepIndex).toBeLessThanOrEqual(steps[1].stepIndex);
  });

  it('getUserCompletion returns completion for a finished user', async () => {
    const completion = await repo.getUserCompletion(PRODUCT, 'user-a');
    expect(completion).not.toBeNull();
    expect(completion!.totalSteps).toBe(3);
    expect(completion!.durationMs).toBe(180000);
  });

  it('getUserCompletion returns null for incomplete user', async () => {
    const completion = await repo.getUserCompletion(PRODUCT, 'user-c');
    expect(completion).toBeNull();
  });

  it('getFunnel for unknown product returns zero counts', async () => {
    const funnel = await repo.getFunnel('nonexistent-product');

    expect(funnel.totalStarted).toBe(0);
    expect(funnel.totalCompleted).toBe(0);
    expect(funnel.completionRate).toBe(0);
    expect(funnel.steps).toHaveLength(0);
    expect(funnel.avgDurationMs).toBeUndefined();
  });
});
