/*
 * 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.stocktaking;

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.catalog.Product;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.BasicType;
import com.arrebol.taxiservicios.model.enums.CheckStatus;
import com.arrebol.taxiservicios.model.stocktaking.CheckStocktaking;
import com.arrebol.taxiservicios.model.stocktaking.CheckStocktakingDetail;
import javax.persistence.criteria.CriteriaQuery;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
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 CheckStocktakingController extends ConnectionManager implements Serializable {
    
    public List<CheckStocktakingDetail> printDetailsFromCheckStocktakingID(CheckStocktaking check) {
        logger.info("findDetailsFromCheckStocktakingID");

        List<CheckStocktakingDetail> results = null;
        Transaction transaction = null;

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

            transaction = session.beginTransaction();

            results = session.createQuery("FROM CheckStocktakingDetail WHERE checkStocktaking = :check and lastStocktaking > 0 ORDER BY product.brand.name")
                    .setParameter("check", check)
                    .getResultList();

            transaction.commit();

            logger.info("CheckStocktakingDetail detail's list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find CheckStocktakingDetail details list", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findDetailsFromCheckStocktakingID()", e);
            rollback(transaction);
        }
        return results;
    }
    
    public List<CheckStocktakingDetail> findDetailsFromCheckStocktakingID(CheckStocktaking check) {
        logger.info("findDetailsFromCheckStocktakingID");

        List<CheckStocktakingDetail> results = null;
        Transaction transaction = null;

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

            transaction = session.beginTransaction();

            results = session.createQuery("FROM CheckStocktakingDetail WHERE checkStocktaking = :check AND "
                    + "lastStocktaking != newStocktaking ORDER BY product.brand.name")
                    .setParameter("check", check)
                    .getResultList();

            transaction.commit();

            logger.info("CheckStocktakingDetail detail's list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find CheckStocktakingDetail details list", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findDetailsFromCheckStocktakingID()", e);
            rollback(transaction);
        }
        return results;
    }
    
    public List<Product> fillProducts() {

        Transaction transaction = null;
        List<Product> result = null;

        try {
            logger.info("Searching all products to select..");
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();

            CriteriaQuery<Product> criteria = builder.createQuery(Product.class);
            Root<Product> root = criteria.from(Product.class);

            criteria.where(builder.and(builder.equal(root.get("activeStatus"), BasicType.ENEBLED), builder.equal(root.get("service"), BasicType.DISABLED)));

            result = session.createQuery(criteria).getResultList();

            logger.info("Total of products found for ComboBox: " + (null == result ? -1 : result.size()));
            transaction.commit();
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load list of products for ComboBox ", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method fillProducts for Invoice", e);
        }

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

            Path<String> id = root.get("id");
            Path<String> description = root.get("description");
            Path<CheckStatus> checkStatus = root.get("checkStatus");
            Path<Boolean> active = root.get("active");
            Path<Date> createdOn = root.get("createdOn");
            Path<User> createdByPath = root.get("createdBy");
            Path<Location> locationPath = root.get("location");
            Path<Person> revisorPath = root.get("revisor");
            Path<Person> ejecutorPath = root.get("ejecutor");

            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));
            Predicate activePredicate = builder.equal(root.get("active"),true);

            query.select(
                    builder.construct(
                            CheckStocktaking.class,
                            id, description, checkStatus,
                            active, createdOn, createdByPath,
                            locationPath, revisorPath, ejecutorPath
                    )
            );
            query.where(builder.and(startDatePredicate, endDatePredicate, locationPredicate, activePredicate));
            query.orderBy(builder.asc(root.get("createdOn")));

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

            transaction.commit();

            logger.info("CheckStocktaking list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find CheckStocktaking between dates", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findBetweenDates()", e);
            rollback(transaction);
        }
        return results;
    }
    
    public boolean save(CheckStocktaking check, List<CheckStocktakingDetail> prds) {
        logger.info("save");

        boolean success = false;
        Transaction transaction = null;

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

            session.save(check);
            
            prds.forEach((CheckStocktakingDetail products) -> {
                session.save(products);
            });

            transaction.commit();
            success = true;
        } catch (HibernateException e) {
            logger.error("Can not save CheckStocktaking", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method save()", e);
            rollback(transaction);
        }
        return success;
    }
    
    public boolean deleteById(String id, User lastUpdatedBy) {
        logger.info("deleteById");

        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<CheckStocktaking> query = builder.createCriteriaUpdate(CheckStocktaking.class);
            Root<CheckStocktaking> root = query.from(CheckStocktaking.class);

            query.set(root.get("active"), false);
            query.set(root.get("lastUpdatedBy"), lastUpdatedBy);
            query.set(root.get("lastUpdatedOn"), new Date());

            query.where(builder.equal(root.get("id"), id));

            int total = session.createQuery(query).executeUpdate();

            if (1 == total) {
                transaction.commit();
                success = true;
                logger.info("delete status successfully");
            } else {
                logger.info("CAN NOT delete CheckStocktaking");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT delete CheckStocktaking", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method deleteById()", e);
            rollback(transaction);
        }
        return success;
    }
    
    public boolean updateById(String id, CheckStatus status, User lastUpdatedBy, String ejecutor, String revisor) {
        logger.info("updateById");

        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<CheckStocktaking> query = builder.createCriteriaUpdate(CheckStocktaking.class);
            Root<CheckStocktaking> root = query.from(CheckStocktaking.class);

            query.set(root.get("checkStatus"), status);
            query.set(root.get("ejecutor"), new Person(ejecutor));
            query.set(root.get("revisor"), new Person(revisor));
            query.set(root.get("lastUpdatedBy"), lastUpdatedBy);
            query.set(root.get("lastUpdatedOn"), new Date());

            query.where(builder.equal(root.get("id"), id));

            int total = session.createQuery(query).executeUpdate();

            if (1 == total) {
                transaction.commit();
                success = true;
                logger.info("Update status successfully");
            } else {
                logger.info("CAN NOT update CheckStocktaking");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT update CheckStocktaking", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateById()", e);
            rollback(transaction);
        }
        return success;
    }
    
    public CheckStocktaking findById(String id) {
        CheckStocktaking result = null;
        Transaction transaction = null;

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

            result = session.find(CheckStocktaking.class, id);

            transaction.commit();
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not found CheckStocktaking by id", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method findById", e);
        }

        return result;
    }
    
    public boolean updateDetailById(CheckStocktakingDetail tmp, User user) {
        logger.info("updateDetailById");

        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<CheckStocktakingDetail> query = builder.createCriteriaUpdate(CheckStocktakingDetail.class);
            Root<CheckStocktakingDetail> root = query.from(CheckStocktakingDetail.class);

            query.set(root.get("newStocktaking"), tmp.getNewStocktaking());
            query.set(root.get("description"), tmp.getDescription());
            query.set(root.get("lastUpdatedOn"), new Date());
            query.set(root.get("lastUpdatedBy"), user);

            query.where(builder.equal(root.get("id"), tmp.getId()));

            int total = session.createQuery(query).executeUpdate();

            if (1 == total) {
                transaction.commit();
                success = true;
                logger.info("Update status successfully");
            } else {
                logger.info("CAN NOT update CheckStocktakingDetail");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT update CheckStocktakingDetail", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateDetailById()", e);
            rollback(transaction);
        }
        return success;
    }
    
    private static final long serialVersionUID = -3049612223190797349L;
    final Logger logger = LogManager.getLogger(CheckStocktakingController.class);
}
