package de.thdeg.grademanager;

import de.thdeg.grademanager.model.CoursesOfStudy;
import de.thdeg.grademanager.model.Student;
import jakarta.persistence.*;

import java.util.List;
import java.util.function.Function;

/**
 * A singleton implementation that encapsulates the JPA logic.
 * You can configure the database connection in the
 * {@link /src/main/resources/META-INF/persistence.xml} file.
 */
public class JpaService
{
    private static JpaService instance;
    private EntityManagerFactory entityManagerFactory;

    private JpaService()
    {
        entityManagerFactory = Persistence.createEntityManagerFactory("jpa-hibernate-notenmanager");
    }

    public static synchronized JpaService getInstance()
    {
        return instance == null ? instance = new JpaService() : instance;
    }

    public void closeResource()
    {
        if(entityManagerFactory != null)
        {
            entityManagerFactory.close();
        }
    }

    public EntityManagerFactory getEntityManagerFactory()
    {
        return entityManagerFactory;
    }

    /**
     * Runs the specified function inside a transaction boundary. The function has
     * access to a ready to use {@link EntityManager} and can return any type of
     * value ({@code T}).
     *
     * @param function The function to run.
     * @param <T>      The function's return type.
     * @return the value returned by the specified function.
     */
    public <T> T runInTransaction(Function <EntityManager, T> function)
    {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        EntityTransaction entityTransaction = entityManager.getTransaction();
        boolean isPersisted = false;

        entityTransaction.begin();

        try
        {
            T returnValue = function.apply(entityManager);
            isPersisted = true;

            return returnValue;
        }
        finally
        {
            if(isPersisted)
            {
                entityTransaction.commit();
            }
            else
            {
                entityTransaction.rollback();
            }
        }
    }

    public List<Student> getStudentsFromDb(){
        EntityManager entityManager = entityManagerFactory.createEntityManager();
       Query query = entityManager.createQuery("SELECT q FROM Student q", Student.class);
        return query.getResultList();
    }

    public List<CoursesOfStudy> getCoursesOfStudyFromDb(){
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        Query query = entityManager.createQuery("SELECT q FROM CoursesOfStudy q", CoursesOfStudy.class);
        return query.getResultList();
    }
}