package dev.fyloz.trial.colorrecipesexplorer.repository

import dev.fyloz.trial.colorrecipesexplorer.model.EmployeeGroup
import dev.fyloz.trial.colorrecipesexplorer.model.employee
import dev.fyloz.trial.colorrecipesexplorer.model.employeeGroup
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
import kotlin.test.*

@DataJpaTest
class EmployeeRepositoryTest @Autowired constructor(private val employeeRepository: EmployeeRepository, val entityManager: TestEntityManager) {
    private var employeeGroup = employeeGroup()
    private val employee = employee(id = 0L, firstName = "fname", lastName = "lname")
    private val anotherEmployee = employee(id = 1L, firstName = "another fname", lastName = "another lname")
    private val groupEmployee = employee(id = 2L, firstName = "group fname", lastName = "group lname", group = employeeGroup)
    private val defaultGroupEmployee = employee(id = 3L, firstName = "default fname", lastName = "default lname", group = employeeGroup, isDefaultGroupUser = true)

    @AfterEach
    fun afterEach() {
        if (employeeGroup.id != null) {
            entityManager.remove(employeeGroup)
            employeeGroup = employeeGroup(id = null)
            groupEmployee.group = employeeGroup
            defaultGroupEmployee.group = employeeGroup
        }
    }

    @Test
    fun `existsByFirstNameAndLastName() returns true when an employee with the given first name and last name exists`() {
        entityManager.persist(employee)

        val exists = employeeRepository.existsByFirstNameAndLastName(employee.firstName, employee.lastName)

        assertTrue(exists)
    }

    @Test
    fun `existsByFirstNameAndLastName() returns false when no employee with the given first name and last name exists`() {
        entityManager.persist(anotherEmployee)

        val exists = employeeRepository.existsByFirstNameAndLastName(employee.firstName, employee.lastName)

        assertFalse(exists)
    }

    @Test
    fun `findByFirstNameAndLastName() returns the employee with the given first name and last name`() {
        val expected = entityManager.persist(employee)
        entityManager.persist(anotherEmployee)    // Persist another employee to make sure the correct one is return by the tested method
        assertNotNull(expected)
        assertNotNull(expected.id)

        val found = employeeRepository.findByFirstNameAndLastName(employee.firstName, employee.lastName)

        assertEquals(found, expected)
    }

    @Test
    fun `findByFirstNameAndLastName() returns null when no employee with the given first name and last name exists`() {
        entityManager.persist(anotherEmployee)

        val found = employeeRepository.findByFirstNameAndLastName(employee.firstName, employee.lastName)

        assertNull(found)
    }

    @Test
    fun `findAllByGroup() returns all employees in the given group`() {
        entityManager.persist(employeeGroup)
        entityManager.persist(employee)
        entityManager.persist(groupEmployee)
        entityManager.persist(defaultGroupEmployee)

        val found = employeeRepository.findAllByGroup(employeeGroup)

        assertTrue(found.contains(groupEmployee))
        assertTrue(found.contains(defaultGroupEmployee))
        assertFalse(found.contains(employee))
    }

    @Test
    fun `findByIsDefaultGroupUserIsTrueAndGroupIs() returns the default employee of the given group`() {
        entityManager.persist(employeeGroup)
        entityManager.persist(employee)
        entityManager.persist(groupEmployee)
        entityManager.persist(defaultGroupEmployee)

        val found = employeeRepository.findByIsDefaultGroupUserIsTrueAndGroupIs(employeeGroup)

        assertEquals(found, defaultGroupEmployee)
    }
}

class EmployeeGroupRepositoryTest @Autowired constructor(employeeGroupRepository: EmployeeGroupRepository, entityManager: TestEntityManager) :
        AbstractNamedJpaRepositoryTest<EmployeeGroup, EmployeeGroupRepository>(employeeGroupRepository, entityManager) {
    override fun entity(name: String): EmployeeGroup = employeeGroup(name = name)
}

