import { testDb, testModules } from '@n8n/backend-test-utils';
import { CredentialsRepository } from '@n8n/db';
import { Container } from '@n8n/di';

import type { DynamicCredentialResolver } from '@/modules/dynamic-credentials.ee/database/entities/credential-resolver';
import { DynamicCredentialResolverRepository } from '@/modules/dynamic-credentials.ee/database/repositories/credential-resolver.repository';

describe('DynamicCredentialResolverRepository', () => {
	let resolverRepository: DynamicCredentialResolverRepository;
	let credentialsRepository: CredentialsRepository;
	let previousEnvVar: string | undefined;

	beforeAll(async () => {
		previousEnvVar = process.env.N8N_ENV_FEAT_DYNAMIC_CREDENTIALS;
		process.env.N8N_ENV_FEAT_DYNAMIC_CREDENTIALS = 'true';
		await testModules.loadModules(['dynamic-credentials']);
		await testDb.init();
		resolverRepository = Container.get(DynamicCredentialResolverRepository);
		credentialsRepository = Container.get(CredentialsRepository);
	});

	afterEach(async () => {
		await testDb.truncate(['CredentialsEntity', 'DynamicCredentialResolver']);
	});

	afterAll(async () => {
		process.env.N8N_ENV_FEAT_DYNAMIC_CREDENTIALS = previousEnvVar;
		await testDb.terminate();
	});

	it('should create and find a resolver', async () => {
		const resolver = resolverRepository.create({
			name: 'Test Resolver',
			type: 'oauth2',
			config: JSON.stringify({ clientId: 'test' }),
		});
		const saved = await resolverRepository.save(resolver);

		const found = await resolverRepository.findOne({ where: { id: saved.id } });

		expect(found).toMatchObject({
			id: saved.id,
			name: 'Test Resolver',
			type: 'oauth2',
		});
	});

	describe('relationship with CredentialsEntity', () => {
		let resolver: DynamicCredentialResolver;

		beforeEach(async () => {
			resolver = await resolverRepository.save(
				resolverRepository.create({
					name: 'Test Resolver',
					type: 'oauth2',
					config: JSON.stringify({}),
				}),
			);
		});

		it('should link credentials to resolver and query them', async () => {
			await credentialsRepository.save([
				credentialsRepository.create({
					name: 'Cred 1',
					type: 'oauth2',
					data: '',
					isResolvable: true,
					resolverId: resolver.id,
				}),
				credentialsRepository.create({
					name: 'Cred 2',
					type: 'oauth2',
					data: '',
					isResolvable: true,
					resolvableAllowFallback: true,
					resolverId: resolver.id,
				}),
			]);

			const linked = await credentialsRepository.find({ where: { resolverId: resolver.id } });

			expect(linked).toHaveLength(2);
			expect(linked[0].resolverId).toBe(resolver.id);
			expect(linked[1].resolvableAllowFallback).toBe(true);
		});

		it('should handle nullable resolverId', async () => {
			const credential = await credentialsRepository.save(
				credentialsRepository.create({
					name: 'Standalone',
					type: 'apiKey',
					data: '',
					isResolvable: false,
				}),
			);

			expect(credential.resolverId).toBeNull();
		});

		it('should set resolverId to null on resolver deletion (CASCADE SET NULL)', async () => {
			const credential = await credentialsRepository.save(
				credentialsRepository.create({
					name: 'Linked',
					type: 'oauth2',
					data: '',
					isResolvable: true,
					resolverId: resolver.id,
				}),
			);

			await resolverRepository.delete(resolver.id);
			const orphaned = await credentialsRepository.findOneBy({ id: credential.id });

			expect(orphaned?.resolverId).toBeNull();
		});
	});
});
