package org.academiadecodigo.bootcamp.fxlogin.service.bootcamp;

import org.academiadecodigo.bootcamp.fxlogin.model.Bootcamp;
import org.academiadecodigo.bootcamp.fxlogin.model.Cadet;
import org.academiadecodigo.bootcamp.fxlogin.utils.JpaUtils;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.util.List;
import java.util.Set;

/**
 * MIT License
 * (c) 2017 Ricardo Constantino
 */

public class JpaBootcampService implements BootcampService {
    private EntityManagerFactory emf;
    private Integer selectedBootcamp;

    public JpaBootcampService(EntityManagerFactory emf) {
        this.emf = emf;
    }

    @Override
    public void createBootcamp(Integer id, Bootcamp.Location location, String start, String end) {
        Bootcamp newBootcamp = new Bootcamp(id, location, start, end);
        addBootcamp(newBootcamp);
    }

    @Override
    public void addBootcamp(Bootcamp bootcamp) {
        JpaUtils<Bootcamp> bootcampJpaUtils = new JpaUtils<>(emf);

        if (getById(bootcamp.getId()) != null) {
            return;
        }

        bootcampJpaUtils.save(bootcamp);
    }

    @Override
    public void addCodeCadet(Integer bootcampId, Cadet cadet) {
        Bootcamp bootcamp = getById(bootcampId);
        JpaUtils<Cadet> cadetJpaUtils = new JpaUtils<>(emf);

        if (bootcamp.getCadets().contains(cadet)) {
            return;
        }

        bootcamp.addCodeCadet(cadet);
        cadet.setBootcamp(bootcamp);
        cadetJpaUtils.save(cadet);
    }

    @Override
    public void addCodeCadets(Integer bootcampId, Cadet... cadets) {
        Bootcamp bootcamp = getById(bootcampId);
        Set<Cadet> cadetsAlreadyAdded = bootcamp.getCadets();
        JpaUtils<Cadet> cadetJpaUtils = new JpaUtils<>(emf);

        for (Cadet cadet : cadets) {
            if (cadetsAlreadyAdded.contains(cadet)) {
                return;
            }

            bootcamp.addCodeCadet(cadet);
            cadet.setBootcamp(bootcamp);
            cadetJpaUtils.save(cadet);
        }

    }

    @Override
    public Bootcamp getById(Integer bootcampId) {
        EntityManager em = emf.createEntityManager();

        try {
            CriteriaBuilder builder = em.getCriteriaBuilder();

            CriteriaQuery<Bootcamp> criteriaQuery = builder.createQuery(Bootcamp.class);

            Root<Bootcamp> bootcampRoot = criteriaQuery.from(Bootcamp.class);

            criteriaQuery.select(bootcampRoot);

            criteriaQuery.where(builder.equal(bootcampRoot.get("id"), bootcampId));

            return em.createQuery(criteriaQuery).getSingleResult();
        } catch (NoResultException e) {
            return null;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    @Override
    public List<Bootcamp> listBootcamps() {
        EntityManager em = emf.createEntityManager();

        try {
            CriteriaBuilder builder = em.getCriteriaBuilder();

            CriteriaQuery<Bootcamp> criteriaQuery = builder.createQuery(Bootcamp.class);

            Root<Bootcamp> bootcampRoot = criteriaQuery.from(Bootcamp.class);

            criteriaQuery.select(bootcampRoot);

            return em.createQuery(criteriaQuery).getResultList();
        } catch (NoResultException e) {
            return null;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    @Override
    public Set<Cadet> listCodeCadets(Integer bootcampId) {
        Bootcamp bootcamp = getById(bootcampId);
        return bootcamp != null ? bootcamp.getCadets() : null;
    }

    @Override
    public void setSelectedBootcamp(Integer bootcampId) {
        selectedBootcamp = bootcampId;
    }

    @Override
    public Integer getSelectedBootcamp() {
        return selectedBootcamp;
    }
}
