/*
 * Arrebol Consultancy copyright.
 * 
 * This code belongs to Arrebol Consultancy
 * its use, redistribution or modification are prohibited 
 * without written authorization from Arrebol Consultancy.
 */
package com.arrebol.taxiservicios.controller.admin;

import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.admin.Expense;
import com.arrebol.taxiservicios.model.admin.TransferMoneyLocation;
import com.arrebol.taxiservicios.model.catalog.Location;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.BasicType;
import com.arrebol.taxiservicios.model.enums.ExpenseStatusType;
import com.arrebol.taxiservicios.model.enums.StatusType;
import com.arrebol.taxiservicios.model.stocktaking.Invoice;
import com.arrebol.taxiservicios.model.view.report.PaymentClient;
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 Carlos Janitzio Zavala Lopez <janitzio.zavala@arrebol.com.mx>
 */
public class TransferMoneyLocationController extends ConnectionManager implements Serializable {

    /**
     *
     * @param date
     * @return
     */
    public boolean existStableGeneralBoxByCreatedOn(Date date, String locationId) {
        logger.info("existStableGeneralBoxByCreatedOn");

        boolean success = true;
        Transaction transaction = null;

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

            String query = "SELECT COUNT(sgb.id) "
                    + "FROM StableGeneralBox sgb "
                    + "WHERE DATE(sgb.createdOn) = DATE(:date) "
                    + "AND sgb.activeStatus = 'ENEBLED' AND sgb.location.id = :locationId";

            Long count = (Long) session.createQuery(query)
                    .setParameter("date", date)
                    .setParameter("locationId", locationId)
                    .uniqueResult();

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

            transaction.commit();

            logger.info("Total of closing day found: " + count);
        } catch (HibernateException e) {
            logger.error("Can not find stable general box by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existStableGeneralBoxByCreatedOn()", e);
            rollback(transaction);
        }

        return success;
    }

    /**
     * Find stable small box between Dates (Start date and End Date).
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public List<TransferMoneyLocation> findTransferMoneyLocationBetweenDates(Date startDate, Date endDate, String idLocation) {
        logger.info("findTransferMoneyLocationBetweenDates");
        List<TransferMoneyLocation> results = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<TransferMoneyLocation> query = builder.createQuery(TransferMoneyLocation.class);
            Root<TransferMoneyLocation> root = query.from(TransferMoneyLocation.class);

            Path<String> id = root.get("id");
            Path<Double> amount = root.get("amount");
            Path<String> description = root.get("description");
            Path<BasicType> autorizacion = root.get("autorizacion");
            Path<Location> locationSend = root.get("locationSend");
            Path<Location> locationReceiver = root.get("locationReceiver");
            Path<Date> createdOn = root.get("createdOn");
            Path<User> createdByPath = root.get("createdBy");
            Path<Location> locationPath = root.get("location");
            Path<Boolean> active = root.get("active");

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

            query.select(
                    builder.construct(
                            TransferMoneyLocation.class,
                            id, amount, description,
                            autorizacion, locationSend, locationReceiver,
                            createdOn, createdByPath, locationPath, active
                    )
            );
            query.where(builder.and(startDatePredicate, endDatePredicate, (builder.or(locationReceiverPredicate, locationPredicate))));
            query.orderBy(builder.asc(root.get("createdOn")));

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

            transaction.commit();

            logger.info("TransferMoneyLocation list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find TransferMoneyLocation between dates", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findTransferMoneyLocationBetweenDates()", e);
            rollback(transaction);
        }
        return results;
    }
    
    public List<Location> findLocation(Location location) {
        logger.info("findTransferMoneyLocationBetweenDates");
        List<Location> results = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<Location> query = builder.createQuery(Location.class);
            Root<Location> root = query.from(Location.class);

            Path<String> id = root.get("id");
            Path<String> name = root.get("name");

            Predicate locationPredicate = builder.notEqual(root.get("id"), location.getId());

            query.select(
                    builder.construct(
                            Location.class,
                            id, name
                    )
            );
            query.where(builder.and(locationPredicate));
            query.orderBy(builder.asc(root.get("createdOn")));

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

            transaction.commit();

            logger.info("findLocation list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find findLocation between dates", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findLocation()", e);
            rollback(transaction);
        }
        return results;
    }

    /**
     * Update active status (ENEBLED/DISABLED) of stable small box by ID.
     *
     * @param id Primary key to be updated.
     * @param status Status to be updated (ENEBLED/DISABLED).
     * @param lastUpdatedBy User to apply update.
     * @return
     */
    public boolean updateTransferMoneyLocationById(String id, BasicType status, User lastUpdatedBy) {
        logger.info("updateTransferMoneyLocationById");

        boolean success = false;
        Transaction transaction = null;

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

            query.set(root.get("autorizacion"), status);
            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 TransferMoneyLocation");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT update TransferMoneyLocation", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateTransferMoneyLocationById()", e);
            rollback(transaction);
        }
        return success;
    }
    
    /**
     * Update active status (ENEBLED/DISABLED) of stable small box by ID.
     *
     * @param id Primary key to be updated.
     * @param status Status to be updated (ENEBLED/DISABLED).
     * @param lastUpdatedBy User to apply update.
     * @return
     */
    public boolean deleteTransferMoneyLocationById(String id, User lastUpdatedBy) {
        logger.info("updateTransferMoneyLocationById");

        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<TransferMoneyLocation> query = builder.createCriteriaUpdate(TransferMoneyLocation.class);
            Root<TransferMoneyLocation> root = query.from(TransferMoneyLocation.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 TransferMoneyLocation");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT delete TransferMoneyLocation", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method deleteTransferMoneyLocationById()", e);
            rollback(transaction);
        }
        return success;
    }

    /**
     * Save a new stable small box entry.
     *
     * @param stableGeneralBox
     * @return
     */
    public boolean save(TransferMoneyLocation transfer) {
        logger.info("save");

        boolean success = false;
        Transaction transaction = null;

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

            session.save(transfer);

            transaction.commit();
            success = true;
        } catch (HibernateException e) {
            logger.error("Can not save TransferMoneyLocation", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method save()", e);
            rollback(transaction);
        }
        return success;
    }

    public List<Invoice> getInvoiceNoPaid(String locationId) {
        logger.info("getInvoiceNoPaid");

        List<Invoice> success = null;
        Transaction transaction = null;

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

            String query = "SELECT invoice "
                    + "FROM Invoice invoice "
                    + "WHERE invoice.paid = 'DISABLED' AND invoice.locationSend.id = :locationId AND invoice.statusType ='APPROVED' ";

            success = session.createQuery(query)
                    .setParameter("locationId", locationId)
                    .getResultList();

            transaction.commit();

            logger.info("Total of closing day found: " + success.size());
        } catch (HibernateException e) {
            logger.error("Can not find stable general box by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existStableGeneralBoxByCreatedOn()", e);
            rollback(transaction);
        }

        return success;
    }
    
    public List<PaymentClient> getPaymentClientNoPaid(String locationId) {
        logger.info("getPaymentClientNoPaid");

        List<PaymentClient> success = null;
        Transaction transaction = null;

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

            String query = "SELECT invoice "
                    + "FROM PaymentClient invoice "
                    + "WHERE invoice.paid = 'DISABLED' AND invoice.locationSend.id = :locationId AND  invoice.actionStatus ='APPROVED'";

            success = session.createQuery(query)
                    .setParameter("locationId", locationId)
                    .getResultList();

            transaction.commit();

            logger.info("Total of closing day found: " + success.size());
        } catch (HibernateException e) {
            logger.error("Can not find stable general box by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existStableGeneralBoxByCreatedOn()", e);
            rollback(transaction);
        }

        return success;
    }
    
    public List<Expense> getExpenseNoPaid(String locationId) {
        logger.info("getExpenseNoPaid");

        List<Expense> success = null;
        Transaction transaction = null;

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

            String query = "SELECT invoice "
                    + "FROM Expense invoice "
                    + "WHERE invoice.paid = 'DISABLED' AND invoice.locationSend.id = :locationId AND invoice.status ='AUTHORIZED'";

            success = session.createQuery(query)
                    .setParameter("locationId", locationId)
                    .getResultList();

            transaction.commit();

            logger.info("Total of closing day found: " + success.size());
        } catch (HibernateException e) {
            logger.error("Can not find stable general box by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existStableGeneralBoxByCreatedOn()", e);
            rollback(transaction);
        }

        return success;
    }
    
     public List<Expense> getExpenseNoPaidPending(String locationId) {
        logger.info("getExpenseNoPaid");

        List<Expense> success = null;
        Transaction transaction = null;

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

            String query = "SELECT invoice "
                    + "FROM Expense invoice "
                    + "WHERE invoice.paid = 'DISABLED' AND invoice.locationSend.id = :locationId AND invoice.status ='PENDING'";

            success = session.createQuery(query)
                    .setParameter("locationId", locationId)
                    .getResultList();

            transaction.commit();

            logger.info("Total of closing day found: " + success.size());
        } catch (HibernateException e) {
            logger.error("Can not find stable general box by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existStableGeneralBoxByCreatedOn()", e);
            rollback(transaction);
        }

        return success;
    }
     
    public boolean autorizarExpense(String expenseId, User user) {
        logger.info("autorizar");

        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<Expense> update = builder.createCriteriaUpdate(Expense.class);
            Root<Expense> rootUpdate = update.from(Expense.class);

            update.set("status", ExpenseStatusType.AUTHORIZED);
            update.set("lastUpdatedBy", user);
            update.set("lastUpdatedOn", new Date());
            update.where(builder.equal(rootUpdate.get("id"), expenseId));

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

            if (1 == total) {
                transaction.commit();
                success = true;
                logger.info("Sale " + expenseId + " updated");
            } else {
                transaction.rollback();
                logger.error("Error Sale updated total: " + total);
            }
        } catch (HibernateException e) {
            logger.error("Sale can not be updated ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method autorizar() ", e);
            rollback(transaction);
        }
        return success;
    }
    
    
    public List<Invoice> getInvoiceNoPaidPending(String locationId) {
        logger.info("getInvoiceNoPaid");

        List<Invoice> success = null;
        Transaction transaction = null;

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

            String query = "SELECT invoice "
                    + "FROM Invoice invoice "
                    + "WHERE invoice.paid = 'DISABLED' AND invoice.locationSend.id = :locationId AND invoice.statusType ='PENDING'";

            success = session.createQuery(query)
                    .setParameter("locationId", locationId)
                    .getResultList();

            transaction.commit();

            logger.info("Total of closing day found: " + success.size());
        } catch (HibernateException e) {
            logger.error("Can not find stable general box by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existStableGeneralBoxByCreatedOn()", e);
            rollback(transaction);
        }

        return success;
    }
    
    public boolean autorizarInvoice(String invoiceId, User user) {
        logger.info("autorizar");

        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<Invoice> update = builder.createCriteriaUpdate(Invoice.class);
            Root<Invoice> rootUpdate = update.from(Invoice.class);

            update.set("statusType", StatusType.APPROVED);
            update.set("lastUpdatedBy", user);
            update.set("lastUpdatedOn", new Date());
            update.where(builder.equal(rootUpdate.get("id"), invoiceId));

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

            if (1 == total) {
                transaction.commit();
                success = true;
                logger.info("Sale " + invoiceId + " updated");
            } else {
                transaction.rollback();
                logger.error("Error Sale updated total: " + total);
            }
        } catch (HibernateException e) {
            logger.error("Sale can not be updated ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method autorizar() ", e);
            rollback(transaction);
        }
        return success;
    }
    
    public List<PaymentClient> getPaymentClientNoPaidPending(String locationId) {
        logger.info("getPaymentClientNoPaid");

        List<PaymentClient> success = null;
        Transaction transaction = null;

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

            String query = "SELECT invoice "
                    + "FROM PaymentClient invoice "
                    + "WHERE invoice.paid = 'DISABLED' AND invoice.locationSend.id = :locationId AND invoice.actionStatus ='PENDING'";

            success = session.createQuery(query)
                    .setParameter("locationId", locationId)
                    .getResultList();

            transaction.commit();

            logger.info("Total of closing day found: " + success.size());
        } catch (HibernateException e) {
            logger.error("Can not find stable general box by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existStableGeneralBoxByCreatedOn()", e);
            rollback(transaction);
        }

        return success;
    }
    
    public boolean autorizarPaymentClient(String invoiceId, User user) {
        logger.info("autorizar");

        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<PaymentClient> update = builder.createCriteriaUpdate(PaymentClient.class);
            Root<PaymentClient> rootUpdate = update.from(PaymentClient.class);

            update.set("actionStatus", StatusType.APPROVED);
            update.set("lastUpdatedBy", user);
            update.set("lastUpdatedOn", new Date());
            update.where(builder.equal(rootUpdate.get("id"), invoiceId));

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

            if (1 == total) {
                transaction.commit();
                success = true;
                logger.info("Sale " + invoiceId + " updated");
            } else {
                transaction.rollback();
                logger.error("Error Sale updated total: " + total);
            }
        } catch (HibernateException e) {
            logger.error("Sale can not be updated ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method autorizar() ", e);
            rollback(transaction);
        }
        return success;
    }
    
  
    public boolean updateInvoiceSetPaid(String id, User lastUpdatedBy) {
        logger.info("updateInvoiceSetPaid");

        boolean success = false;
        Transaction transaction = null;

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

            query.set(root.get("paid"), BasicType.ENEBLED);
            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 Invoice");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT update Invoice", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateInvoiceSetPaid()", e);
            rollback(transaction);
        }
        return success;
    }
    
    public boolean updatePaymentClientSetPaid(String id, User lastUpdatedBy) {
        logger.info("updatePaymentClientSetPaid");

        boolean success = false;
        Transaction transaction = null;

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

            query.set(root.get("paid"), BasicType.ENEBLED);
            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 PaymentClient");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT update PaymentClient", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updatePaymentClientSetPaid()", e);
            rollback(transaction);
        }
        return success;
    }
    
    public boolean updateExpenseSetPaid(String id, User lastUpdatedBy) {
        logger.info("updateExpenseSetPaid");

        boolean success = false;
        Transaction transaction = null;

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

            query.set(root.get("paid"), BasicType.ENEBLED);
            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 Expense");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT update Expense", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateExpenseSetPaid()", e);
            rollback(transaction);
        }
        return success;
    }


    private static final long serialVersionUID = -3049612223190797349L;
    final Logger logger = LogManager.getLogger(TransferMoneyLocationController.class);

}
