package dst.ass1.jpa.tests;

import static dst.ass1.jpa.CaseInsensitiveStringCollectionMatcher.hasItems;
import static dst.ass1.jpa.util.Constants.*;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;

import org.junit.Before;
import org.junit.ClassRule;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
import org.junit.runners.MethodSorters;

import dst.ass1.jpa.DatabaseGateway;
import dst.ass1.jpa.ORMService;
import dst.ass1.jpa.util.Constants;

/**
 * Tests the basic object-relational mapping by examining the created database tables and constraints.
 */
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class Ass1_1_1_01Test {

    @ClassRule
    public static ORMService orm = new ORMService();

    @Rule
    public ErrorCollector err = new ErrorCollector();

    private DatabaseGateway db;

    @Before
    public void setUp() throws Exception {
        db = orm.getDatabaseGateway();
    }

    @Test
    public void printTables() throws Exception {
        // not a test, just some systout output that may help you to gain insight into the created database schema
        for (String table : db.getTables()) {
            System.out.printf("%-30s %s%n", table, db.getColumns(table));
        }
    }

    @Test
    public void testBasicTablesJdbc() throws Exception {
        // checks that all basic tables exist
        err.checkThat(db.getTables(), hasItems(
                T_LECTURER,
                T_PARTICIPANT,
                T_MEMBERSHIP,
                T_LESSON,
                T_COURSE,
                T_ENROLLMENT,
                T_COURSEPLATFORM,
                T_MATERIAL,
                T_METADATA,
                T_MATERIALSERVER
        ));
    }

    @Test
    public void testRelation01Jdbc() throws Exception {
        // lecturer <-> lesson
        err.checkThat(db.getTables(), hasItems(J_LECTURER_LESSON));
        err.checkThat(db.getColumns(J_LECTURER_LESSON), hasItems(
                I_LESSON,
                I_LECTURER
        ));
    }

    @Test
    public void testRelation02Jdbc() throws Exception {
        // lecturer <-> course
        err.checkThat(db.getColumns(T_COURSE), hasItems(I_LECTURER));
    }

    @Test
    public void testRelation03Jdbc() throws Exception {
        // participant <-enrollment-> course

        err.checkThat(db.getColumns(T_ENROLLMENT), hasItems(
                I_PARTICIPANT,
                I_COURSE
        ));
        err.checkThat(db.getTables(), hasItems(
                J_COURSE_ENROLLMENT,
                J_PARTICIPANT_ENROLLMENT
        ));
    }

    @Test
    public void testRelation04Jdbc() throws Exception {
        // participant <-> membership -> courseplatform

        err.checkThat(db.getColumns(T_MEMBERSHIP), hasItems(
                I_COURSEPLATFORM,
                I_PARTICIPANT
        ));
        err.checkThat(db.getColumns(T_PARTICIPANT), not(hasItems(I_MEMBERSHIP)));
        err.checkThat(db.getColumns(T_COURSEPLATFORM), not(hasItems(I_MEMBERSHIP)));

        err.checkThat(db.getTables(), hasItems(J_PARTICIPANT_MEMBERSHIP));
        err.checkThat(db.getColumns(J_PARTICIPANT_MEMBERSHIP), hasItems(I_PARTICIPANT));
    }

    @Test
    public void testRelation05Jdbc() throws Exception {
        // lesson <-> lesson

        err.checkThat("join table should be explicitly renamed!", db.getTables(), not(hasItems(
                T_LESSON + "_" + T_LESSON
        )));
        err.checkThat(db.getTables(), hasItems(
                J_LESSONS_REQUIRED
        ));
        err.checkThat(db.getColumns(J_LESSONS_REQUIRED), hasItems(
                I_LESSON_REQUIRED,
                I_LESSON_REQUIRED_BY
        ));
    }

    @Test
    public void testRelation06Jdbc() throws Exception {
        // lesson <-> course
        err.checkThat(db.getColumns(T_LESSON), hasItems(I_COURSE));
        err.checkThat(db.getColumns(T_COURSE), not(hasItems(I_LESSON)));
        err.checkThat(db.isIndex(T_LESSON, I_COURSE, true), is(true));
    }

    @Test
    public void testRelation07Jdbc() throws Exception {
        // lesson <-> material

        err.checkThat(db.getColumns(T_MATERIAL), hasItems(I_LESSON));
        err.checkThat(db.getColumns(T_LESSON), not(hasItems(I_MATERIAL)));
        err.checkThat(db.isIndex(T_MATERIAL, I_LESSON, true), is(true));
    }

    @Test
    public void testRelation08Jdbc() throws Exception {
        // course -> courseplatform
        err.checkThat(db.getColumns(T_COURSE), hasItems(I_COURSEPLATFORM));
        err.checkThat(db.isIndex(T_COURSE, I_COURSEPLATFORM, true), is(true));
    }

    @Test
    public void testRelation09Jdbc() throws Exception {
        // course -> metadata
        err.checkThat(db.getTables(), hasItems(T_METADATA));
        err.checkThat(db.getColumns(T_COURSE), hasItems(I_METADATA));
        err.checkThat(db.getColumns(T_METADATA), not(hasItems(I_COURSE)));
        err.checkThat(db.isIndex(Constants.T_COURSE, Constants.I_METADATA, false), is(true));

    }

    @Test
    public void testRelation10Jdbc() throws Exception {
        // courseplatform -> materialserver
        err.checkThat(db.getTables(), hasItems(J_COURSEPLATFORM_MATERIALSERVER));
        err.checkThat(db.getColumns(T_MATERIALSERVER), not(hasItems(I_COURSEPLATFORM)));
    }

    @Test
    public void testRelation11Jdbc() throws Exception {
        // material <-> materialserver

        err.checkThat(db.getTables(), hasItems(J_MATERIALSERVER_MATERIAL));
    }

    @Test
    public void testColumnType01Jdbc() {
        err.checkThat(db.isColumnInTableWithType(T_PARTICIPANT, M_PERSON_PASSWORD, "VARBINARY", "20"), is(true));
    }

}
