import 'reflect-metadata';

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

import { NOTIFICATION_GATEWAY_REGISTRY_TOKEN, NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN, NOTIFICATION_REPOSITORY_TOKEN, NOTIFICATION_SERVICE_TOKEN } from './NotificationsPersistenceTokens';

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

  afterEach(() => {
    process.env = originalEnv;
    vi.restoreAllMocks();
  });

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

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

    const { NotificationsPersistenceModule } = await import('./NotificationsPersistenceModule');
    const { InMemoryNotificationRepository } = await import('@adapters/notifications/persistence/inmemory/InMemoryNotificationRepository');
    const { InMemoryNotificationPreferenceRepository } = await import('@adapters/notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository');
    const { NotificationServiceAdapter } = await import('@adapters/notifications/ports/NotificationServiceAdapter');

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

    const notificationRepo = module.get(NOTIFICATION_REPOSITORY_TOKEN);
    expect(notificationRepo).toBeInstanceOf(InMemoryNotificationRepository);

    const preferenceRepo = module.get(NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN);
    expect(preferenceRepo).toBeInstanceOf(InMemoryNotificationPreferenceRepository);

    const notificationService = module.get(NOTIFICATION_SERVICE_TOKEN);
    expect(notificationService).toBeInstanceOf(NotificationServiceAdapter);

    const gatewayRegistry = module.get(NOTIFICATION_GATEWAY_REGISTRY_TOKEN);
    expect(gatewayRegistry).toBeDefined();

    await module.close();
  });

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

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

    const { NotificationsPersistenceModule } = await import('./NotificationsPersistenceModule');
    const { PostgresNotificationsPersistenceModule } = await import('../postgres/PostgresNotificationsPersistenceModule');

    const imports = Reflect.getMetadata(MODULE_METADATA.IMPORTS, NotificationsPersistenceModule) as unknown[];
    expect(imports).toContain(PostgresNotificationsPersistenceModule);
  });

  it('defaults to inmemory when GRIDPILOT_API_PERSISTENCE is not set', async () => {
    vi.resetModules();

    delete process.env.GRIDPILOT_API_PERSISTENCE;
    delete process.env.DATABASE_URL;

    const { NotificationsPersistenceModule } = await import('./NotificationsPersistenceModule');
    const { InMemoryNotificationsPersistenceModule } = await import('../inmemory/InMemoryNotificationsPersistenceModule');

    const imports = Reflect.getMetadata(MODULE_METADATA.IMPORTS, NotificationsPersistenceModule) as unknown[];
    expect(imports).toContain(InMemoryNotificationsPersistenceModule);
  });
});