import 'reflect-metadata';

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

import { DatabaseModule } from '../../domain/database/DatabaseModule';
import { PostgresSocialPersistenceModule } from '../postgres/PostgresSocialPersistenceModule';
import { SOCIAL_FEED_REPOSITORY_TOKEN, SOCIAL_GRAPH_REPOSITORY_TOKEN } from './SocialPersistenceTokens';

import type { FeedRepository } from '@core/social/domain/repositories/FeedRepository';
import type { SocialGraphRepository } from '@core/social/domain/repositories/SocialGraphRepository';

import { DriverOrmEntity } from '@adapters/racing/persistence/typeorm/entities/DriverOrmEntity';
import { FeedItemOrmEntity } from '@adapters/social/persistence/typeorm/entities/FeedItemOrmEntity';
import { FriendshipOrmEntity } from '@adapters/social/persistence/typeorm/entities/FriendshipOrmEntity';

describe('PostgresSocialPersistenceModule (integration)', () => {
  const shouldRun = Boolean(process.env.DATABASE_URL);

  afterEach(() => {
    delete process.env.GRIDPILOT_API_PERSISTENCE;
  });

  (shouldRun ? it : it.skip)('reads driver feed against a real database', async () => {
    process.env.GRIDPILOT_API_PERSISTENCE = 'postgres';

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

    const dataSource = module.get<DataSource>(getDataSourceToken());

    const driverRepo = dataSource.getRepository(DriverOrmEntity);
    const friendshipRepo = dataSource.getRepository(FriendshipOrmEntity);
    const feedOrmRepo = dataSource.getRepository(FeedItemOrmEntity);

    await feedOrmRepo.clear();
    await friendshipRepo.clear();
    await driverRepo.clear();

    const driverA = new DriverOrmEntity();
    driverA.id = '00000000-0000-0000-0000-000000000001';
    driverA.iracingId = '1';
    driverA.name = 'A';
    driverA.country = 'DE';
    driverA.bio = null;
    driverA.joinedAt = new Date('2025-01-01T00:00:00.000Z');

    const driverB = new DriverOrmEntity();
    driverB.id = '00000000-0000-0000-0000-000000000002';
    driverB.iracingId = '2';
    driverB.name = 'B';
    driverB.country = 'DE';
    driverB.bio = null;
    driverB.joinedAt = new Date('2025-01-01T00:00:00.000Z');

    await driverRepo.save([driverA, driverB]);

    const friendship = new FriendshipOrmEntity();
    friendship.driverId = driverA.id;
    friendship.friendId = driverB.id;
    friendship.createdAt = new Date('2025-01-01T00:00:00.000Z');
    await friendshipRepo.save(friendship);

    const item = new FeedItemOrmEntity();
    item.id = '00000000-0000-0000-0000-0000000000aa';
    item.timestamp = new Date('2025-02-01T00:00:00.000Z');
    item.type = 'new-result-posted';
    item.actorFriendId = null;
    item.actorDriverId = driverB.id;
    item.leagueId = null;
    item.raceId = null;
    item.teamId = null;
    item.position = null;
    item.headline = 'Hello';
    item.body = null;
    item.ctaLabel = null;
    item.ctaHref = null;

    await feedOrmRepo.save(item);

    const feedRepo = module.get<FeedRepository>(SOCIAL_FEED_REPOSITORY_TOKEN);
    const socialGraphRepo = module.get<SocialGraphRepository>(SOCIAL_GRAPH_REPOSITORY_TOKEN);

    const friendIds = await socialGraphRepo.getFriendIds(driverA.id);
    expect(friendIds).toEqual([driverB.id]);

    const feed = await feedRepo.getFeedForDriver(driverA.id);
    expect(feed).toHaveLength(1);
    expect(feed[0]?.id).toBe(item.id);

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