import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { Logger } from '@core/shared/application';
import { PageView } from '@core/analytics';
import { InMemoryPageViewRepository } from './InMemoryPageViewRepository';

describe('InMemoryPageViewRepository', () => {
  let repository: InMemoryPageViewRepository;
  let mockLogger: Logger;

  beforeEach(() => {
    mockLogger = {
      debug: vi.fn(),
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
    } as unknown as Logger;

    repository = new InMemoryPageViewRepository(mockLogger);
    repository.clear();
  });

  it('initializes with a logger', () => {
    expect(repository).toBeDefined();
    expect(mockLogger.info).toHaveBeenCalledWith('InMemoryPageViewRepository initialized.');
  });

  it('saves and queries page views', async () => {
    const pv1 = PageView.create({
      id: 'pv-1',
      entityType: 'league',
      entityId: 'league-1',
      visitorType: 'anonymous',
      sessionId: 'sess-1',
      visitorId: 'visitor-1',
      timestamp: new Date('2025-01-01T10:00:00.000Z'),
    });
    const pv2 = PageView.create({
      id: 'pv-2',
      entityType: 'league',
      entityId: 'league-1',
      visitorType: 'anonymous',
      sessionId: 'sess-2',
      visitorId: 'visitor-1',
      timestamp: new Date('2025-01-02T10:00:00.000Z'),
    });
    const pv3 = PageView.create({
      id: 'pv-3',
      entityType: 'league',
      entityId: 'league-1',
      visitorType: 'anonymous',
      sessionId: 'sess-3',
      // no visitorId; should fall back to sessionId for uniqueness
      timestamp: new Date('2025-01-02T11:00:00.000Z'),
    });

    await repository.save(pv1);
    await repository.save(pv2);
    await repository.save(pv3);

    expect((await repository.findById('pv-1'))?.id).toBe('pv-1');
    expect((await repository.findByEntityId('league', 'league-1')).length).toBe(3);

    const range = await repository.findByDateRange(
      new Date('2025-01-02T00:00:00.000Z'),
      new Date('2025-01-02T23:59:59.999Z'),
    );
    expect(range.map(p => p.id).sort()).toEqual(['pv-2', 'pv-3']);

    expect((await repository.findBySession('sess-2')).map(p => p.id)).toEqual(['pv-2']);

    const count = await repository.countByEntityId('league', 'league-1');
    expect(count).toBe(3);

    const unique = await repository.countUniqueVisitors('league', 'league-1');
    // visitor-1 + sess-3
    expect(unique).toBe(2);
  });

  it('seeds page views', async () => {
    const pv = PageView.create({
      id: 'seed-pv',
      entityType: 'team',
      entityId: 'team-1',
      visitorType: 'anonymous',
      sessionId: 'sess-seed',
    });

    repository.seed([pv]);
    expect((await repository.findById('seed-pv'))?.id).toBe('seed-pv');
  });
});
