package dst.ass1.jpa.tests;

import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.hamcrest.core.IsCollectionContaining.hasItems;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;

import javax.persistence.EntityManager;

import org.hibernate.Session;
import org.junit.Test;

import dst.ass1.jpa.dao.ILessonDAO;
import dst.ass1.jpa.dao.impl.DAOFactory;
import dst.ass1.jpa.model.ILesson;
import dst.ass1.jpa.util.Constants;

/**
 * Tests the self reference of ILesson.
 */
public class Ass1_1_1_10Test extends Ass1_TestBase {

    @Test
    public void testLessonSelfAssociation() {
        EntityManager em = orm.createEntityManager();
        ILessonDAO dao = new DAOFactory(em).createLessonDAO();

        ILesson lesson1 = dao.findById(testData.lesson1Id);
        ILesson lesson2 = dao.findById(testData.lesson2Id);
        ILesson lesson3 = dao.findById(testData.lesson3Id);
        ILesson lesson4 = dao.findById(testData.lesson4Id);
        assertNotNull(lesson1.getRequiredByLessons());
        assertNotNull(lesson2.getRequiredLessons());
        assertNotNull(lesson2.getRequiredByLessons());
        assertNotNull(lesson3.getRequiredLessons());
        assertNotNull(lesson3.getRequiredByLessons());
        assertNotNull(lesson4.getRequiredLessons());

        List<Long> lesson1requiredBy = map(lesson1.getRequiredByLessons(), ILesson::getId);
        List<Long> lesson2required = map(lesson2.getRequiredLessons(), ILesson::getId);
        List<Long> lesson2requiredBy = map(lesson2.getRequiredByLessons(), ILesson::getId);
        List<Long> lesson3required = map(lesson3.getRequiredLessons(), ILesson::getId);
        List<Long> lesson3requiredBy = map(lesson3.getRequiredByLessons(), ILesson::getId);
        List<Long> lesson4required = map(lesson4.getRequiredLessons(), ILesson::getId);

        assertThat(lesson1requiredBy, hasItems(testData.lesson2Id, testData.lesson3Id));
        assertThat(lesson2required, hasItem(testData.lesson1Id));
        assertThat(lesson3required, hasItem(testData.lesson1Id));
        assertThat(lesson2requiredBy, hasItem(testData.lesson4Id));
        assertThat(lesson3requiredBy, hasItem(testData.lesson4Id));
        assertThat(lesson4required, hasItems(testData.lesson2Id, testData.lesson3Id));
    }

    @Test
    public void testLessonSelfAssociationJdbc() {
        String sql = "SELECT " + Constants.I_LESSON_REQUIRED + ", " + Constants.I_LESSON_REQUIRED_BY +
                " FROM " + Constants.J_LESSONS_REQUIRED +
                " ORDER BY " + Constants.I_LESSON_REQUIRED + ", " + Constants.I_LESSON_REQUIRED_BY;

        em.unwrap(Session.class).doWork(connection -> {

            try (Statement stmt = connection.createStatement()) {
                ResultSet rs = stmt.executeQuery(sql);
                assertTrue(rs.next());

                assertEquals((long) testData.lesson1Id, rs.getLong(Constants.I_LESSON_REQUIRED));
                assertEquals((long) testData.lesson2Id, rs.getLong(Constants.I_LESSON_REQUIRED_BY));

                assertTrue(rs.next());

                assertEquals((long) testData.lesson1Id, rs.getLong(Constants.I_LESSON_REQUIRED));
                assertEquals((long) testData.lesson3Id, rs.getLong(Constants.I_LESSON_REQUIRED_BY));

                assertTrue(rs.next());

                assertEquals((long) testData.lesson2Id, rs.getLong(Constants.I_LESSON_REQUIRED));
                assertEquals((long) testData.lesson4Id, rs.getLong(Constants.I_LESSON_REQUIRED_BY));

                assertTrue(rs.next());

                assertEquals((long) testData.lesson3Id, rs.getLong(Constants.I_LESSON_REQUIRED));
                assertEquals((long) testData.lesson4Id, rs.getLong(Constants.I_LESSON_REQUIRED_BY));

                assertFalse(rs.next());

                rs.close();
            }
        });
    }

}
