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

import 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.StableSmallBox;
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.mutual.MutualStableSmallBox;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
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;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query;

/**
 *
 * @author Carlos Janitzio Zavala Lopez <janitzio.zavala@arrebol.com.mx>
 */
public class MutualStableSmallBoxController extends ConnectionManager implements Serializable {

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

        boolean success = true;
        Transaction transaction = null;

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

            String query = "SELECT ssb.id "
                    + "FROM MUTUAL_STABLE_SMALL_BOX ssb "
                    + "WHERE DATE(ssb.created_on) >= DATE_ADD(DATE(:date), INTERVAL 1 DAY) "
                    + "AND ssb.active_status = 'ENEBLED' AND ssb.id_location = :locationId ";

            List<String> records = session.createSQLQuery(query)
                    .setParameter("date", date)
                    .setParameter("locationId", locationId)
                    .getResultList();

            if (records.isEmpty()) {
                success = false;
            }

            transaction.commit();

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

        return success;
    }

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

            Path<String> id = root.get("id");
            Path<BigDecimal> totalSmallBox = root.get("totalSmallBox");
            Path<BigDecimal> totalEnvelope = root.get("totalEnvelope");
            Path<BigDecimal> totalBankNote = root.get("totalBankNote");
            Path<BigDecimal> totalCoin = root.get("totalCoin");
            Path<BigDecimal> totalStable = root.get("totalStable");
            Path<BigDecimal> totalTransfer = root.get("totalTransfer");
            Path<String> description = root.get("description");
            Path<Date> createdOn = root.get("createdOn");
            Path<User> createdByPath = root.get("createdBy");
            Path<Location> locationPath = root.get("location");
            Path<Boolean> activeStatusPath = root.get("activeStatus");

            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(
                            MutualStableSmallBox.class,
                            id, totalSmallBox, totalEnvelope,
                            totalBankNote, totalCoin, totalStable,
                            description, createdOn, createdByPath, locationPath, activeStatusPath, totalTransfer
                    )
            );
            query.where(builder.and(startDatePredicate, endDatePredicate, locationPredicate));
            query.orderBy(builder.asc(root.get("createdOn")));

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

            transaction.commit();

            logger.info("Stable General Box's list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find stable small box between dates", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findStableSmallBoxBetweenDates()", 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 updateStableSmallBoxById(String id, BasicType status, User lastUpdatedBy) {
        logger.info("updateStableSmallBoxById");

        boolean success = false;
        Transaction transaction = null;

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

            query.set(root.get("activeStatus"), 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 stable small box");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT update stable small box", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateStableSmallBoxById()", e);
            rollback(transaction);
        }
        return success;
    }

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

        boolean success = false;
        Transaction transaction = null;

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

            session.save(stableGeneralBox);

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

    /**
     * Find an entry that match with date (dd/mm/yyyy).
     *
     * @param date
     * @param locationId
     * @return True if exist a coincidence otherwise false.
     */
    public boolean existStableSmallBoxEqToDate(Date date, String locationId) {
        logger.info("existStableSmallBoxEqToDate");

        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            String queryStr = "SELECT COUNT(ssb.id) FROM MutualStableSmallBox ssb WHERE DATE(ssb.createdOn) = DATE(:date) AND ssb.activeStatus = 'ENEBLED' AND location = :location";

            Query query = session.createQuery(queryStr);
            query.setParameter("date", date);
            query.setParameter("location", new Location(locationId));
            success = (Long) (query.getSingleResult()) > 0;

            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not load the stable small box", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existStableSmallBoxEqToDate()", e);
            rollback(transaction);
        }
        return success;
    }

    /**
     *
     * @return
     */
    public BigDecimal getTotalInBox(String locationId) {
        logger.info("getTotalInBox");

        BigDecimal total = null;
        Transaction transaction = null;

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

            String sqlQuery = "SELECT IF(ISNULL(SUM(amount_paid)),0,SUM(amount_paid)) FROM MUTUAL_CLOSING_DAY \n" +
            "WHERE DATE(created_on) > (SELECT DATE(sgb.created_on) FROM MUTUAL_STABLE_SMALL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND id_location = '"+locationId+"' AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1) \n" +
            "AND active_status = 'ENEBLED' AND id_location = '"+locationId+"'";

            NativeQuery nativeQuery = session.createSQLQuery(sqlQuery);

            total = (BigDecimal) (nativeQuery.uniqueResult());
            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not load the total in stable small box", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getTotalInBox()", e);
            rollback(transaction);
        }

        return total;
    }
    
    public BigDecimal getTotalInTransferBox(String locationId) {
        logger.info("getTotalInBox");

        BigDecimal total = null;
        Transaction transaction = null;

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

            String sqlQuery = "SELECT IF(ISNULL(SUM(amount_transfer)),0,SUM(amount_transfer)) FROM MUTUAL_CLOSING_DAY \n" +
            "WHERE DATE(created_on) > (SELECT DATE(sgb.created_on) FROM MUTUAL_STABLE_SMALL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND id_location = '"+locationId+"' AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1) \n" +
            "AND active_status = 'ENEBLED' AND id_location = '"+locationId+"'";

            NativeQuery nativeQuery = session.createSQLQuery(sqlQuery);

            total = (BigDecimal) (nativeQuery.uniqueResult());
            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not load the total in stable small box", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getTotalInBox()", e);
            rollback(transaction);
        }

        return total;
    }

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

}
