import type { Logger } from '@core/shared/domain/Logger';
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
import type { EngagementRepository } from '../../domain/repositories/EngagementRepository';
import type { EntityType } from '../../domain/types/PageView';
import type { PageViewRepository } from '../repositories/PageViewRepository';
import { GetEntityAnalyticsQuery, type GetEntityAnalyticsInput } from './GetEntityAnalyticsQuery';

describe('GetEntityAnalyticsQuery', () => {
  let pageViewRepository: {
    countByEntityId: Mock;
    countUniqueVisitors: Mock;
  };
  let engagementRepository: {
    getSponsorClicksForEntity: Mock;
  };
  let logger: Logger;
  let useCase: GetEntityAnalyticsQuery;

  beforeEach(() => {
    pageViewRepository = {
      countByEntityId: vi.fn(),
      countUniqueVisitors: vi.fn(),
    };

    engagementRepository = {
      getSponsorClicksForEntity: vi.fn(),
    };

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

    useCase = new GetEntityAnalyticsQuery(
      pageViewRepository as unknown as PageViewRepository,
      engagementRepository as unknown as EngagementRepository,
      logger,
    );
  });

  it('aggregates entity analytics and returns summary and trends', async () => {
    const input: GetEntityAnalyticsInput = {
      entityType: 'league' as EntityType,
      entityId: 'league-1',
      period: 'weekly',
    };

    pageViewRepository.countByEntityId
      .mockResolvedValueOnce(100) // current period total page views
      .mockResolvedValueOnce(150); // previous period full page views

    pageViewRepository.countUniqueVisitors
      .mockResolvedValueOnce(40) // current period uniques
      .mockResolvedValueOnce(60); // previous period full uniques

    engagementRepository.getSponsorClicksForEntity
      .mockResolvedValueOnce(10) // current clicks
      .mockResolvedValueOnce(5); // for engagement score

    const result = await useCase.execute(input);

    expect(result.isOk()).toBe(true);
    const data = result.unwrap();
    expect(data.entityId).toBe(input.entityId);
    expect(data.entityType).toBe(input.entityType);

    expect(data.summary.totalPageViews).toBe(100);
    expect(data.summary.uniqueVisitors).toBe(40);
    expect(data.summary.sponsorClicks).toBe(10);
    expect(typeof data.summary.engagementScore).toBe('number');
    expect(data.summary.exposureValue).toBeGreaterThan(0);

    expect(data.trends.pageViewsChange).toBeDefined();
    expect(data.trends.uniqueVisitorsChange).toBeDefined();

    expect(data.period.start).toBeInstanceOf(Date);
    expect(data.period.end).toBeInstanceOf(Date);
  });

  it('propagates repository errors', async () => {
    const input: GetEntityAnalyticsInput = {
      entityType: 'league' as EntityType,
      entityId: 'league-1',
    };

    pageViewRepository.countByEntityId.mockRejectedValue(new Error('DB error'));

    const result = await useCase.execute(input);

    expect(result.isErr()).toBe(true);
    expect((logger.error as unknown as Mock)).toHaveBeenCalled();
  });
});
