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

import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.catalog.Brand;
import com.arrebol.taxiservicios.model.catalog.ClaveProductoServicio;
import com.arrebol.taxiservicios.model.catalog.ClaveUnidad;
import com.arrebol.taxiservicios.model.catalog.Product;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.BasicType;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
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 oscarvargas
 */
public class ProductController extends ConnectionManager implements Serializable {

    /**
     *
     * @param id
     * @return
     */
    public Product findProductById(String id) {
        Product product = null;
        Transaction transaction = null;

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

            product = session.find(Product.class, id);

            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not find product by id", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findProductById of Product", e);
            rollback(transaction);
        }

        return product;
    }

    /**
     *
     * @param isProductName
     * @param textToSearch
     * @return
     */
    public List<Product> searchProductsLikeField(boolean isProductName, String textToSearch) {
        Transaction transaction = null;
        List<Product> result = null;

        try {
            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);

            Path<String> idPath = root.get("id");
            Path<String> namePath = root.get("name");
            Path<String> codePath = root.get("code");

            criteria.select(builder.construct(Product.class, idPath, namePath, codePath));
            Predicate like = isProductName ? builder.like(root.get("name"), textToSearch) : builder.like(root.get("code"), textToSearch);
            Predicate predicate = builder.equal(root.get("activeStatus"), BasicType.ENEBLED);
            
            criteria.where(like,
                    builder.and(
                            predicate
                    ));
            criteria.orderBy((isProductName ? builder.asc(root.get("name")) : builder.asc(root.get("code"))));

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

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

        return result;
    }

    /**
     *
     * @param brandId
     * @return
     */
    public List<Product> searchProductByBrand(String brandId) {

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

        try {
            logger.info("Searching all products..");
            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);
/*
            Path<String> idPath = root.get("id");
            Path<String> namePath = root.get("name");
            Path<String> codePath = root.get("code");
            Path<String> amountPath = root.get("amount");
            Path<String> amount2Path = root.get("amount2");
            Path<String> utilityPath = root.get("utility");
            Path<String> utility2Path = root.get("utility2");
            Path<String> quantityPath = root.get("quantity");
            Path<String> brandPath = root.get("brand");
            Path<Integer> lifePath = root.get("life");
            Path<String> quantity2Path = root.get("quantity2");
            Path<String> tipoUsoPath = root.get("tipoUso");
            Path<String> compatibilidadPath = root.get("compatibilidad");
            Path<BasicType> servicioPath = root.get("service");
            Path<ClaveUnidad> claveUnidadPath = root.get("claveUnidad");
            Path<ClaveProductoServicio> claveProductoServicioPath = root.get("claveProductoServicio");

            criteria.select(
                    builder.construct(Product.class, idPath, namePath, codePath,
                            amountPath, utilityPath, quantityPath, brandPath, lifePath, quantity2Path, tipoUsoPath, compatibilidadPath, 
                            amount2Path, utility2Path, servicioPath, claveUnidadPath, claveProductoServicioPath));
            */
            Predicate predicate = builder.equal(root.get("activeStatus"), BasicType.ENEBLED);
            criteria.where(builder.equal(root.get("brand"), new Brand(brandId)),
                    builder.and(
                            predicate
                    ));
            criteria.orderBy(builder.asc(root.get("name")));

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

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

        return result;
    }

    /**
     *
     * Searching all Products.
     *
     * @return
     */
    public List<Product> fillProductDatatable() {

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

        try {
            logger.info("Searching all products..");
            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);
/*
            Path<String> idPath = root.get("id");
            Path<String> namePath = root.get("name");
            Path<String> codePath = root.get("code");
            Path<String> amountPath = root.get("amount");
            Path<String> amount2Path = root.get("amount2");
            Path<String> utilityPath = root.get("utility");
            Path<String> utility2Path = root.get("utility2");
            Path<String> quantityPath = root.get("quantity");
            Path<String> brandPath = root.get("brand");
            Path<Integer> lifePath = root.get("life");
            Path<String> quantity2Path = root.get("quantity2");
            Path<String> tipoUsoPath = root.get("tipoUso");
            Path<String> compatibilidadPath = root.get("compatibilidad");
            Path<BasicType> servicioPath = root.get("service");
            Path<ClaveUnidad> claveUnidadPath = root.get("claveUnidad");
            Path<ClaveProductoServicio> claveProductoServicioPath = root.get("claveProductoServicio");

            criteria.select(
                    builder.construct(Product.class, idPath, namePath, codePath,
                            amountPath, utilityPath, quantityPath, brandPath, lifePath, quantity2Path, tipoUsoPath, compatibilidadPath, 
                            amount2Path, utility2Path, servicioPath, claveUnidadPath, claveProductoServicioPath));*/
            criteria.where(builder.equal(root.get("activeStatus"), BasicType.ENEBLED));
            criteria.orderBy(builder.asc(root.get("name")));

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

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

        return result;
    }

    public boolean saveProduct(Product product, String userId, String brandId) {
        boolean success = false;
        Transaction transaction = null;

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

            if (product.getId() != null) {
                CriteriaUpdate<Product> update = builder.createCriteriaUpdate(Product.class);
                Root<Product> root = update.from(Product.class);

                update.set("name", product.getName());
                update.set("lastUpdatedBy", new User(userId, ""));
                update.set("lastUpdatedOn", new Date());
                if(!"nada".equals(brandId)){
                    update.set("brand", new Brand(brandId));
                }                
                update.set("quantity", product.getQuantity());
                update.set("utility", product.getUtility());
                update.set("utility2", product.getUtility2());
                update.set("code", product.getCode());
                update.set("amount", product.getAmount());
                update.set("amount2", product.getAmount2());
                update.set("life", product.getLife());
                update.set("quantity2", product.getQuantity2());
                update.set("tipoUso", product.getTipoUso());
                update.set("compatibilidad", product.getCompatibilidad());
                update.set("service", product.getService());
                update.set("herramienta", product.getHerramienta());
                update.set("claveUnidad",product.getClaveUnidad());
                update.set("claveProductoServicio",product.getClaveProductoServicio());

                update.where(builder.equal(root.get("id"), product.getId()));

                session.createQuery(update).executeUpdate();

                logger.info("The product was edited - " + product);

            } else {

                product.setId(UUID.randomUUID().toString());
                product.setCreatedBy(new User(userId, ""));
                product.setCreatedOn(new Date());
                if(!"nada".equals(brandId)){
                    product.setBrand(new Brand(brandId));
                }                  

                session.save(product);
                logger.info("The product was saved - " + product);
            }

            transaction.commit();
            success = true;
        } catch (HibernateException e) {
            logger.error("The product can not be saved - " + product, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method saveProduct(" + product + ")", e);
            rollback(transaction);
        }
        return success;
    }

    public void deleteProduct(Product product) {

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

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

                update.set(("activeStatus"), BasicType.DISABLED);

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

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

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

            }
        } catch (HibernateException e) {
            logger.error("The product can not be deleted - " + product, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method  deleteProduct(" + product + ")", e);
            rollback(transaction);
        }
    }

    private static final long serialVersionUID = -6251140789373986268L;

    final Logger logger = LogManager.getLogger(ProductController.class);

    public ProductController() {
    }

}
