import 'reflect-metadata';

import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { DataSource } from 'typeorm';

import { User } from '@core/identity/domain/entities/User';
import { EmailAddress } from '@core/identity/domain/value-objects/EmailAddress';
import { PasswordHash } from '@core/identity/domain/value-objects/PasswordHash';
import { UserId } from '@core/identity/domain/value-objects/UserId';

import { UserOrmEntity } from '@adapters/identity/persistence/typeorm/entities/UserOrmEntity';
import { TypeOrmAuthRepository } from '@adapters/identity/persistence/typeorm/repositories/TypeOrmAuthRepository';
import { TypeOrmUserRepository } from '@adapters/identity/persistence/typeorm/repositories/TypeOrmUserRepository';
import { UserOrmMapper } from '@adapters/identity/persistence/typeorm/mappers/UserOrmMapper';

const databaseUrl = process.env.DATABASE_URL;
const describeIfDatabase = databaseUrl ? describe : describe.skip;

describeIfDatabase('TypeORM Identity repositories (postgres slice)', () => {
  let dataSource: DataSource;

  beforeAll(async () => {
    if (!databaseUrl) {
      throw new Error('DATABASE_URL is required to run postgres integration tests');
    }

    dataSource = new DataSource({
      type: 'postgres',
      url: databaseUrl,
      entities: [UserOrmEntity],
      synchronize: true,
    });

    await dataSource.initialize();
  });

  afterAll(async () => {
    if (dataSource?.isInitialized) {
      await dataSource.destroy();
    }
  });

  it('supports: persist user + find by email + update displayName', async () => {
    const mapper = new UserOrmMapper();
    const userRepo = new TypeOrmUserRepository(dataSource, mapper);
    const authRepo = new TypeOrmAuthRepository(dataSource, mapper);

    const email = EmailAddress.create(`it-${Date.now()}@example.com`);
    const passwordHash = PasswordHash.fromHash('bcrypt-hash-for-it');
    const userId = UserId.create();

    const user = User.create({
      id: userId,
      email: email.value,
      displayName: 'Integration User',
      passwordHash,
    });

    await authRepo.save(user);

    const loaded = await authRepo.findByEmail(email);
    expect(loaded).not.toBeNull();
    expect(loaded!.getId().value).toBe(user.getId().value);
    expect(loaded!.getEmail()).toBe(email.value.toLowerCase());
    expect(loaded!.getDisplayName()).toBe('Integration User');

    const stored = await userRepo.findByEmail(email.value.toUpperCase());
    expect(stored).not.toBeNull();
    expect(stored!.email).toBe(email.value.toLowerCase());

    const updated = User.create({
      id: userId,
      email: email.value,
      displayName: 'Integration User Updated',
      passwordHash,
    });

    await authRepo.save(updated);

    const loadedUpdated = await authRepo.findByEmail(email);
    expect(loadedUpdated!.getDisplayName()).toBe('Integration User Updated');
  });
});