import 'reflect-metadata';

import type { TestingModule } from '@nestjs/testing';
import { Test } from '@nestjs/testing';
import { afterEach, describe, expect, it, vi } from 'vitest';

import {
    ANALYTICS_ENGAGEMENT_REPOSITORY_TOKEN,
    ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN,
    ANALYTICS_SNAPSHOT_REPOSITORY_TOKEN,
} from './AnalyticsPersistenceTokens';

describe('AnalyticsPersistenceModule', () => {
  const originalEnv = { ...process.env };

  afterEach(() => {
    process.env = originalEnv;
    delete (globalThis as { __GP_TEST_DATA_SOURCE__?: unknown }).__GP_TEST_DATA_SOURCE__;
    vi.restoreAllMocks();
    vi.resetModules();
    vi.unmock('@nestjs/typeorm');
  });

  it('uses inmemory providers when GRIDPILOT_API_PERSISTENCE=inmemory', async () => {
    vi.resetModules();

    process.env.GRIDPILOT_API_PERSISTENCE = 'inmemory';
    delete process.env.DATABASE_URL;

    const { AnalyticsPersistenceModule } = await import('./AnalyticsPersistenceModule');
    const { InMemoryPageViewRepository } = await import('@adapters/analytics/persistence/inmemory/InMemoryPageViewRepository');
    const { InMemoryEngagementRepository } = await import('@adapters/analytics/persistence/inmemory/InMemoryEngagementRepository');
    const { InMemoryAnalyticsSnapshotRepository } = await import('@adapters/analytics/persistence/inmemory/InMemoryAnalyticsSnapshotRepository');

    const module: TestingModule = await Test.createTestingModule({
      imports: [AnalyticsPersistenceModule],
    }).compile();

    expect(module.get(ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN)).toBeInstanceOf(InMemoryPageViewRepository);
    expect(module.get(ANALYTICS_ENGAGEMENT_REPOSITORY_TOKEN)).toBeInstanceOf(InMemoryEngagementRepository);
    expect(module.get(ANALYTICS_SNAPSHOT_REPOSITORY_TOKEN)).toBeInstanceOf(InMemoryAnalyticsSnapshotRepository);

    await module.close();
  });

  it('uses postgres providers when GRIDPILOT_API_PERSISTENCE=postgres', async () => {
    vi.resetModules();

    process.env.GRIDPILOT_API_PERSISTENCE = 'postgres';
    delete process.env.DATABASE_URL;

    const DATA_SOURCE_TOKEN = 'TEST_DATA_SOURCE_TOKEN';

    const fakeDataSource = {
      getRepository: () => ({}),
    };

    (globalThis as { __GP_TEST_DATA_SOURCE__?: unknown }).__GP_TEST_DATA_SOURCE__ = fakeDataSource;

    vi.doMock('@nestjs/typeorm', async () => {
      return {
        TypeOrmModule: {
          forFeature: () => ({
            module: class TypeOrmFeatureStubModule {},
            providers: [
              {
                provide: DATA_SOURCE_TOKEN,
                useValue: (globalThis as { __GP_TEST_DATA_SOURCE__?: unknown }).__GP_TEST_DATA_SOURCE__,
              },
            ],
            exports: [DATA_SOURCE_TOKEN],
          }),
        },
        getDataSourceToken: () => DATA_SOURCE_TOKEN,
      };
    });

    const { AnalyticsPersistenceModule } = await import('./AnalyticsPersistenceModule');
    const { TypeOrmPageViewRepository } = await import('@adapters/analytics/persistence/typeorm/repositories/TypeOrmPageViewRepository');
    const { TypeOrmEngagementRepository } = await import('@adapters/analytics/persistence/typeorm/repositories/TypeOrmEngagementRepository');
    const { TypeOrmAnalyticsSnapshotRepository } = await import('@adapters/analytics/persistence/typeorm/repositories/TypeOrmAnalyticsSnapshotRepository');

    const module: TestingModule = await Test.createTestingModule({
      imports: [AnalyticsPersistenceModule],
    }).compile();

    expect(module.get(ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN)).toBeInstanceOf(TypeOrmPageViewRepository);
    expect(module.get(ANALYTICS_ENGAGEMENT_REPOSITORY_TOKEN)).toBeInstanceOf(TypeOrmEngagementRepository);
    expect(module.get(ANALYTICS_SNAPSHOT_REPOSITORY_TOKEN)).toBeInstanceOf(TypeOrmAnalyticsSnapshotRepository);

    await module.close();
  });
});