/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.arrebol.taxiservicios.controller.payroll;

import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.catalog.Location;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.payroll.Payroll;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @author Oscar
 */
public class PayrollController extends ConnectionManager implements Serializable {
    
    public boolean existPayrollByUserThisWeek(String idUser) {
        logger.info("existPayrollByUserThisWeek");

        boolean success = true;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT COUNT(sgb.id) "
                    + "FROM PAYROLL sgb "
                    + "WHERE WEEK(DATE(sgb.createdOn)) = WEEK(CURDATE()) AND YEAR(DATE(sgb.createdOn)) = YEAR(CURDATE()) AND sgb.user = :user"
                    + "AND sgb.active = 1";

            Long count = (Long) session.createQuery(query).setParameter("user", new User(idUser, true)).uniqueResult();

            if (null != count && count == 0) {
                success = false;
            }

            transaction.commit();

            logger.info("Total of payroll found: " + count);
        } catch (HibernateException e) {
            logger.error("Can not find payroll by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existPayrollByUserThisWeek()", e);
            rollback(transaction);
        }

        return success;
    }
    
    public List<Payroll> findPayrollBetweenDates(Date startDate, Date endDate, String idLocation) {
        logger.info("findPayrollBetweenDates");
        List<Payroll> results = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<Payroll> query = builder.createQuery(Payroll.class);
            Root<Payroll> root = query.from(Payroll.class);

            Path<String> id = root.get("id");
            Path<User> user = root.get("user");
            Path<Double> salary = root.get("salary");
            Path<Double> imss = root.get("imss");
            Path<Double> increase = root.get("increase");
            Path<Double> discount = root.get("discount");
            Path<String> descriptionIncrease = root.get("descriptionIncrease");
            Path<String> descriptionDiscount = root.get("descriptionDiscount");
            Path<Double> cajeado = root.get("cajeado");
            Path<Double> adelanto = root.get("adelanto");
            Path<Double> total = root.get("total");
            Path<Date> createdOn = root.get("createdOn");
            Path<User> createdByPath = root.get("createdBy");
            Path<Location> locationPath = root.get("location");
            Path<Date> initDate = root.get("initDate");
            Path<Date> endDateP = root.get("endDate");
            Path<Double> saving = root.get("saving");
            Path<Boolean> active = root.get("active");
            Path<Double> abono = root.get("abono");

            Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("createdOn"), startDate);
            Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("createdOn"), endDate);
            Predicate locationPredicate = builder.equal(root.get("location"), new Location(idLocation));

            query.select(
                    builder.construct(
                            Payroll.class,
                            id, user, salary,
                            imss, increase, discount,
                            descriptionIncrease, descriptionDiscount, cajeado, adelanto,
                            total, createdOn, createdByPath, locationPath, initDate, endDateP, saving, active, abono
                    )
            );
            query.where(builder.and(startDatePredicate, endDatePredicate, locationPredicate));
            query.orderBy(builder.asc(root.get("createdOn")));

            results = session.createQuery(query).getResultList();

            transaction.commit();

            logger.info("Payroll list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find Payroll between dates", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findPayrollBetweenDates()", e);
            rollback(transaction);
        }
        return results;
    }
    
    public boolean save(Payroll payroll) {
        logger.info("saveStableSmallBox");

        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            session.save(payroll);

            transaction.commit();
            success = true;
        } catch (HibernateException e) {
            logger.error("Can not save payroll", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method save()", e);
            rollback(transaction);
        }
        return success;
    }
    
    public double getAdvanceByUser(Person employee) {
        logger.info("getAdvanceByUser");

        Transaction transaction = null;
        double advance = 0D;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT SUM(sgb.amount) "
                    + "FROM Adelantos sgb "
                    + "WHERE WEEK(DATE(sgb.createdOn)) = WEEK(CURDATE()) AND YEAR(DATE(sgb.createdOn)) = YEAR(CURDATE()) AND sgb.employee = :user "
                    + "AND sgb.active = 1";

            advance = (double) session.createQuery(query).setParameter("user", employee).uniqueResult();

            transaction.commit();

            logger.info("Total of advance found: " + advance);
        } catch (HibernateException e) {
            logger.error("Can not find advance by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getAdvanceByUser()", e);
            rollback(transaction);
        }

        return advance;
    }
    
    public void delete(Payroll payroll) {

        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();

            if (payroll.getId() != null) {            
                
                CriteriaUpdate<Payroll> update = builder.createCriteriaUpdate(Payroll.class);
                Root<Payroll> rootPerson = update.from(Payroll.class);

                update.set(("active"), Boolean.FALSE);

                update.where(builder.equal(rootPerson.get("id"), payroll.getId()));

                int total = session.createQuery(update).executeUpdate();
                
                if (1 == total) {
                    logger.info("The payroll was deleted - " + payroll.getId());
                    transaction.commit();

                } else {
                    logger.error("payroll can not be updated " + payroll.getId());
                    transaction.rollback();
                }

            }
        } catch (HibernateException e) {
            logger.error("The payroll can not be deleted - " + payroll, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method  delete(" + payroll + ")", e);
            rollback(transaction);
        }
    }
    
    public boolean existPayrrollBetweenDates(User user, Date startDate, Date endDate) {
        logger.info("existPayrrollBetweenDates");

        boolean success = true;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT COUNT(ssb.id) "
                    + "FROM Payroll ssb "
                    + "WHERE DATE(ssb.initDate) = :startDate " 
                    + "AND DATE(ssb.endDate) = :endDate "
                    + "AND ssb.active = 1 "
                    + "AND ssb.user = :user";

            Long count = (Long) session.createQuery(query)
                    .setParameter("startDate", startDate)
                    .setParameter("endDate", endDate)
                    .setParameter("user", user)
                    .uniqueResult();

            if (null != count && count == 0) {
                success = false;
            }

            transaction.commit();

            logger.info("Total of Payroll found: " + count);
        } catch (HibernateException e) {
            logger.error("Can not find Payroll by created by", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existPayrrollBetweenDates()", e);
            rollback(transaction);
        }

        return success;
    }
    
    
    private static final long serialVersionUID = -3049612223190797349L;
    final Logger logger = LogManager.getLogger(PayrollController.class);
    
}
