import { TestBed } from '@automock/jest'
import { User } from '@backend/domain'
import { TableSubscriberRepository, UserCredentialsRepository, UserRepository } from '@backend/repository'
import { ForbiddenException, NotFoundException } from '@nestjs/common'
import { randomUUID } from 'node:crypto'
import { UserService } from './user.service'

jest.mock('typeorm-transactional', () => ({
	Transactional: () => () => ({}),
}))

describe('User Service', () => {
	let userService: UserService
	let userRepository: jest.Mocked<UserRepository>
	let userCredentialsRepository: jest.Mocked<UserCredentialsRepository>
	let tableSubscriberRepository: jest.Mocked<TableSubscriberRepository>

	beforeAll(() => {
		const { unit, unitRef } = TestBed.create(UserService).compile()
		userService = unit
		userRepository = unitRef.get(UserRepository)
		userCredentialsRepository = unitRef.get(UserCredentialsRepository)
		tableSubscriberRepository = unitRef.get(TableSubscriberRepository)
	})

	describe('deleteById method', () => {
		it('should soft delete user', async () => {
			const id = randomUUID()
			const user = { id } as User
			userRepository.findOne.mockResolvedValue(user)
			userCredentialsRepository.delete.mockImplementation()
			tableSubscriberRepository.delete.mockImplementation()
			await userService.deleteById(id)
			expect(userRepository.softDelete).toHaveBeenCalledTimes(1)
			expect(userCredentialsRepository.delete).toHaveBeenCalledTimes(1)
			expect(tableSubscriberRepository.delete).toHaveBeenCalledTimes(1)
		})

		it('should throw NotFoundException if user does not exist', async () => {
			const id = randomUUID()
			userRepository.findOne.mockResolvedValue(null)
			await expect(userService.deleteById(id)).rejects.toThrow(new NotFoundException('User not found'))
		})

		it('should throw error if user with provided id is admin', async () => {
			const id = randomUUID()
			const user = { id, isAdmin: true } as User
			userRepository.findOne.mockResolvedValue(user)
			await expect(userService.deleteById(id)).rejects.toThrow(new ForbiddenException(`Admin user cannot be deleted`))
		})
	})
})
