/*
 * 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.apc.controller.admin;

import com.arrebol.apc.controller.util.ConnectionManager;
import com.arrebol.apc.controller.util.HibernateUtil;
import com.arrebol.apc.model.ModelParameter;
import com.arrebol.apc.model.admin.ExpenseCompany;
import com.arrebol.apc.model.admin.StableGeneralBox;
import com.arrebol.apc.model.admin.constance.StableGeneralBoxCfg;
import com.arrebol.apc.model.core.Office;
import com.arrebol.apc.model.enums.ActiveStatus;
import com.arrebol.apc.model.views.GeneralBoxView;
import com.arrebol.apc.model.views.ResumenTotalWeekView;
import com.arrebol.apc.model.views.constance.GeneralBoxViewCfg;
import com.arrebol.apc.repository.GenericEntityRepository;
import java.io.Serializable;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
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 Armando Vargas Cardenas <oscar.vargas@arrebol.com.mx>
 */
public class StableGeneralBoxController extends ConnectionManager implements Serializable {

    /**
     *
     * Searching all stable general box by office.
     *
     * @param officeId
     * @param startDate
     * @param endDate
     * @return
     */
    public List<StableGeneralBox> fillStableGeneralBoxDatatable(String officeId, Date startDate, Date endDate) {
        logger.debug("fillStableGeneralBoxDatatable");
        List<ModelParameter> parameters = new ArrayList<>();
        
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        calendar.add(Calendar.DAY_OF_YEAR, 1);
        startDate = calendar.getTime();

        Calendar calendarF = Calendar.getInstance();
        calendarF.setTime(endDate);
        calendarF.add(Calendar.DAY_OF_YEAR, 1);
        endDate = calendarF.getTime();
        
        parameters.add(new ModelParameter(StableGeneralBoxCfg.FIELD_OFFICE, new Office(officeId)));
        //parameters.add(new ModelParameter(StableGeneralBoxCfg.FIELD_ACTIVE_STATUS, ActiveStatus.ENEBLED));
        parameters.add(new ModelParameter(StableGeneralBoxCfg.PARAM_START_DATE, startDate));
        parameters.add(new ModelParameter(StableGeneralBoxCfg.PARAM_END_DATE, endDate));

        return genericEntityRepository.xmlQueryAPCEntities(StableGeneralBox.class, StableGeneralBoxCfg.QUERY_FIND_ALL_STABLE_GENERAL_BOX_BY_OFFICE_BETWEEN_DATES, parameters);
    }

    /**
     *
     * @param status
     * @param stableGeneralBoxIdToUpdate
     * @param lastUpdatedBy
     * @return
     */
    public boolean updateStableGeneralBoxByStatus(ActiveStatus status, String stableGeneralBoxIdToUpdate, String lastUpdatedBy) {
        logger.debug("updateStableGeneralBoxByStatus");

        List<ModelParameter> parameters = new ArrayList<>();

        parameters.add(new ModelParameter(StableGeneralBoxCfg.FIELD_ACTIVE_STATUS, status));
        parameters.add(new ModelParameter(StableGeneralBoxCfg.FIELD_LAST_UPDATED_BY, lastUpdatedBy));
        parameters.add(new ModelParameter(StableGeneralBoxCfg.FIELD_LAST_UPDATED_ON, new Date()));
        parameters.add(new ModelParameter(StableGeneralBoxCfg.FIELD_ID, stableGeneralBoxIdToUpdate));

        return genericEntityRepository.xmlUpdateOrDeleteAPCEntity(StableGeneralBoxCfg.QUERY_UPDATE_STABLE_GENERAL_BOX_BY_STATUS, parameters);
    }

    /**
     *
     * @param stableGeneralBox
     * @return boolean
     */
    public boolean saveStableGeneralBox(StableGeneralBox stableGeneralBox) {
        logger.debug("saveStableGeneralBox");
        boolean success = genericEntityRepository.insertAPCEntity(stableGeneralBox);

        return success;
    }
    
    public boolean autoSaveEntry(ExpenseCompany expense){
        logger.debug("autoSaveEntry");
        boolean success = genericEntityRepository.insertAPCEntity(expense);

        return success;
    }

    /**
     *
     * Searching all details by general box by office.
     *
     * @param officeId
     * @return
     */
    public List<GeneralBoxView> findAllGeneralBox(String officeId) {
        logger.debug("findAllGeneralBox");
        List<ModelParameter> parameters = new ArrayList<>();

        parameters.add(new ModelParameter(GeneralBoxViewCfg.FIELD_OFFICE, officeId));

        return genericEntityRepository.xmlQueryAPCEntities(GeneralBoxView.class, GeneralBoxViewCfg.QUERY_FIND_ALL_DETAILS, parameters);
    }

    /**
     *
     * Searching the stable general box by date and office
     *
     * @param createdOn
     * @param officeid
     * @return
     */
    public Long getCountStableGeneralBoxByOfficeAndDate(Date createdOn, String officeid) {
        logger.debug("getClosingDayCurdateByUserId");
        List<ModelParameter> parameters = new ArrayList<>();

        parameters.add(new ModelParameter(StableGeneralBoxCfg.FIELD_CREATEDON, createdOn));
        parameters.add(new ModelParameter(StableGeneralBoxCfg.FIELD_OFFICE, new Office(officeid)));

        return (Long) genericEntityRepository.xmlQueryAPCEntityUniqueResult(Long.class, StableGeneralBoxCfg.QUERY_COUNT_STABLE_GENERAL_BOX_BY_OFFICE_AND_DATE, parameters);
    }
    
        /**
     *
     * Searching the stable small box by date and office
     *
     * @param officeid
     * @return
     */
    public BigDecimal getPendingByClosingDay(String officeid) {
        logger.debug("getPendingByClosingDay");
        List<ModelParameter> parameters = new ArrayList<>();

        parameters.add(new ModelParameter(StableGeneralBoxCfg.FIELD_OFFICE_VIEW, officeid));

        return (BigDecimal) genericEntityRepository.xmlQueryAPCEntityUniqueResult(BigDecimal.class, StableGeneralBoxCfg.QUERY_SUM_PENDING_CLOSING_BY_OFFICE, parameters);
    }

    /**
     *
     * @param date
     * @return
     */
    public boolean existNextPaidStableGeneralBoxByCreatedOn(Date date) {
        logger.info("existNextPaidStableGeneralBoxByCreatedOn");

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

        return genericEntityRepository.existRecordsUsingSQLQueryFindByCreatedOnField(date, query);
    }

    public BigDecimal getTotalBox() {
        logger.info("getTotalBox");
        BigDecimal totalBox = BigDecimal.ZERO;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            
            List<Object> rows = session.createNativeQuery(queryTotalBox).getResultList();
            
            transaction.commit();
            
            if (rows != null) {
                totalBox = (BigDecimal) rows.get(0);
//                Object[] results = (Object[]) rows.get(0);
//                totalBox = new BigDecimal(results[0] == null ? "0.0" : results[11].toString());
            } else {
                totalBox = BigDecimal.ZERO;
            }
            
        } catch (HibernateException e) {
            logger.error("General Box - getTotalBox( )", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getTotalBox( ) ", e);
            rollback(transaction);
        }
        
        return totalBox;    
    }
    
    final Logger logger = LogManager.getLogger(StableGeneralBoxController.class);
    private final GenericEntityRepository genericEntityRepository;

    public StableGeneralBoxController() {
        this.genericEntityRepository = new GenericEntityRepository();
    }

    public List<Object> getDataReport(Date fecha) {
        DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
        String dateFormat = formatter.format(fecha);

        String queryReport = generalBoxReport;
        queryReport = queryReport.replace(":dateReport", dateFormat);
        List<Object> rows = new ArrayList<>();
        Transaction transaction = null;

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

            //rows = session.createNativeQuery(queryReport).setParameter("dateReport", dateFormat).getResultList();
            rows = session.createNativeQuery(queryReport).getResultList();

            transaction.commit();

        } catch (HibernateException e) {
            logger.error("Driver", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getDataReport(" + fecha + " " + ") ", e);
            rollback(transaction);
        }

        return rows;
    }
    
    String queryTotalBox
            = "SELECT \n"
            + "( \n"
            + "	(CASE \n"
            + "		WHEN \n"
            + "			(SELECT COUNT(total_general_box) AS total_in_box FROM APC_STABLE_GENERAL_BOX WHERE DATE(created_on) < CURDATE() AND active_status = 'ENEBLED' ORDER BY created_on DESC LIMIT 1) > 0 \n"
            + "		THEN \n"
            + "			(SELECT IF(ISNULL(total_general_box),0,total_general_box) AS total_in_box FROM APC_STABLE_GENERAL_BOX WHERE DATE(created_on) < CURDATE() AND active_status = 'ENEBLED' ORDER BY created_on DESC LIMIT 1) \n"
            + "		ELSE 0 \n"
            + "	END) \n"
            // + "    -- Entradas\n"
            + "	+ (SELECT IF(ISNULL(SUM(amount)),0,SUM(amount)) AS total_payment_in_today FROM APC_EXPENSE_COMPANY WHERE expense_company_type = 'PAYMENT_IN' AND DATE(created_on) > (SELECT DATE(sgb.created_on) FROM APC_STABLE_GENERAL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1) AND active_status = 'ENEBLED') \n"
            // + "	-- Salidas\n"
            + "    - (SELECT IF(ISNULL(SUM(amount)),0,SUM(amount)) AS total_payment_out_today FROM APC_EXPENSE_COMPANY WHERE expense_company_type = 'PAYMENT_OUT' AND DATE(created_on) > (SELECT DATE(sgb.created_on) FROM APC_STABLE_GENERAL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1) AND active_status = 'ENEBLED') \n"
            // + "	-- Inicios\n"
            + "    - (SELECT IF(ISNULL(SUM(amount)),0,SUM(amount)) AS payment FROM APC_MONEY_DAILY WHERE DATE(created_on) > (SELECT DATE(sgb.created_on) FROM APC_STABLE_GENERAL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1)) \n"
            // + "    -- Adelantos\n"
            + "    - (SELECT IF(ISNULL(SUM(amount)),0,SUM(amount)) AS total_advances_today FROM APC_ADVANCE WHERE DATE(created_on) > (SELECT DATE(sgb.created_on) FROM APC_STABLE_GENERAL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1) AND active_status = 'ENEBLED') \n"
            // + "    -- Nóminas\n"
            + "    - (SELECT IF(ISNULL(SUM(total_payment)),0,SUM(total_payment)) AS total_payroll_today FROM APC_PAYROLL WHERE DATE(created_on) > (SELECT DATE(sgb.created_on) FROM APC_STABLE_GENERAL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1) AND active_status = 'ENEBLED') \n"
            // + "    -- Préstamo empleados\n"
            + "    - (SELECT IF(ISNULL(SUM(amount_loan)),0,SUM(amount_loan)) AS total_loan_employee_today FROM APC_LOAN_EMPLOYEE WHERE loan_employee_status = 'ENEBLED' AND DATE(created_on) > (SELECT DATE(sgb.created_on) FROM APC_STABLE_GENERAL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1)) \n"
            // + "	-- Caja Chica\n"
            + "    + (SELECT IF(ISNULL(SUM(total_envelope)),0,SUM(total_envelope)) + IF(ISNULL(SUM(total_bank_note)),0,SUM(total_bank_note)) + IF(ISNULL(SUM(total_coin)),0,SUM(total_coin)) AS payment FROM APC_STABLE_SMALL_BOX WHERE active_status = 'ENEBLED' AND DATE(created_on) > (SELECT DATE(sgb.created_on) FROM APC_STABLE_GENERAL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1)) \n" 
            // + "	-- DISPOSICIÓN DE AHORRO\n"
            + "    - (SELECT IF(ISNULL(SUM(employee_saving)),0,SUM(employee_saving)) AS payment FROM APC_EMPLOYEE_SAVING WHERE type = 'DISPOSAL' AND DATE(created_on) > (SELECT DATE(sgb.created_on) FROM APC_STABLE_GENERAL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1)) \n"
            // + "	-- ABONO A PRESTAMO FUERA DE NOMINA\n"
            + "    + (SELECT IF(ISNULL(SUM(payment_amount)),0,SUM(payment_amount)) AS payment FROM APC_LOAN_EMPLOYEE_DETAIL WHERE loan_employee_detail_status = 'ENEBLED' AND payroll = 'DISABLED' AND DATE(created_on) > (SELECT DATE(sgb.created_on) FROM APC_STABLE_GENERAL_BOX sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1)) \n"
            
            + ")AS TOTAL FROM DUAL;";
    
    String generalBoxReport
            = "SELECT\n"
            + "u.id,\n"
            + "-- Inicios\n"
            + "(SELECT IF(ISNULL(SUM(md.amount)),0,SUM(md.amount)) \n"
            + "FROM APC_MONEY_DAILY md\n"
            + "WHERE DATE(md.money_daily_date) = DATE(':dateReport') AND md.id_office = u.id) as money_daily_today,\n"
            + "-- nominas\n"
            + "(SELECT IF(ISNULL(SUM(ap.total_payment)),0,SUM(ap.total_payment)) FROM APC_PAYROLL ap \n"
            + "WHERE ap.id_office = u.id AND ap.active_status = 'ENEBLED' \n"
            + "AND DATE(ap.created_on) = DATE(':dateReport')) as nomina_today,\n"
            + "-- adelantos\n"
            + "(SELECT IF(ISNULL(SUM(ap.amount)),0,SUM(ap.amount)) FROM APC_ADVANCE ap \n"
            + "WHERE ap.id_office = u.id AND ap.active_status = 'ENEBLED' \n"
            + "AND DATE(ap.created_on) = DATE(':dateReport')) as adelantos_today,\n"
            + "-- entradas\n"
            + "(SELECT IF(ISNULL(SUM(ap.amount)),0,SUM(ap.amount)) FROM APC_EXPENSE_COMPANY ap \n"
            + "WHERE ap.id_office = u.id AND ap.active_status = 'ENEBLED' AND \n"
            + "ap.expense_company_type = 'PAYMENT_IN'\n"
            + "AND DATE(ap.created_on) = DATE(':dateReport')) as entradas_today, \n"
            + "-- gastos admon\n"
            + "(SELECT IF(ISNULL(SUM(ap.amount)),0,SUM(ap.amount)) FROM APC_EXPENSE_COMPANY ap \n"
            + "WHERE ap.id_office = u.id AND ap.active_status = 'ENEBLED' AND \n"
            + "ap.expense_company_type = 'PAYMENT_OUT'\n"
            + "AND DATE(ap.created_on) = DATE(':dateReport')) as gastos_admon_today,\n"
            + "-- total caja chica\n"
            + "(SELECT total_small_box FROM APC_STABLE_SMALL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) total_caja_chica_today,\n"
            + "(SELECT total_envelope FROM APC_STABLE_SMALL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) sobres_caja_chica_today,\n"
            + "(SELECT total_bank_note FROM APC_STABLE_SMALL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) efectivo_caja_chica_today,\n"
            + "(SELECT total_coin FROM APC_STABLE_SMALL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) monedas_caja_chica_today,\n"
            + " (SELECT total_stable FROM APC_STABLE_SMALL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) cuadre_caja_chica_today,\n"
            + "  (SELECT description FROM APC_STABLE_SMALL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) descripcion_caja_chica_today,\n"
            + " (SELECT total_general_box FROM APC_STABLE_GENERAL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) total_caja_general_today,\n"
            + "(SELECT total_envelope FROM APC_STABLE_GENERAL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) sobres_caja_general_today,\n"
            + "(SELECT total_bank_note FROM APC_STABLE_GENERAL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) efectivo_caja_general_today,\n"
            + "(SELECT total_coin FROM APC_STABLE_GENERAL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) monedas_caja_general_today,\n"
            + " (SELECT total_stable FROM APC_STABLE_GENERAL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) cuadre_caja_general_today,\n"
            + "  (SELECT description FROM APC_STABLE_GENERAL_BOX where active_status = 'ENEBLED'\n"
            + " AND DATE(created_on) = DATE(':dateReport')) descripcion_caja_general_today,\n"
            + " -- Cortes\n"
            + "(SELECT IF(ISNULL(SUM(ld.amount_paid)),0,SUM(ld.amount_paid)) \n"
            + "FROM APC_CLOSING_DAY ld\n"
            + "WHERE DATE(ld.created_on) = DATE(':dateReport') AND ld.active_status = 'ENEBLED' \n"
            + "AND ld.id_office = u.id) as closing_day_today,\n"
            + "-- Subtotal\n"
            + "(SELECT IF(ISNULL(SUM(ld.payment_amount)),0,SUM(ld.payment_amount)) \n"
            + "FROM APC_LOAN_DETAIL ld\n"
            + "INNER JOIN APC_LOAN l ON l.id = ld.id_loan \n"
            + "INNER JOIN APC_LOAN_BY_USER lbu ON lbu.id_loan = l.id\n"
            + "WHERE DATE(ld.created_on) = DATE(':dateReport') \n"
            + "AND ld.loan_details_type IN ('PAYMENT','RENOVATION_PAYMENT','TRANSFER')) as subtotal_today,\n"
            + "-- comision por apertura\n"
            + "(SELECT IF(ISNULL(SUM(alt.opening_fee)),0,SUM(alt.opening_fee)) FROM APC_LOAN al \n"
            + "    INNER JOIN APC_LOAN_TYPE alt ON al.id_loan_type = alt.id \n"
            + "    INNER JOIN APC_LOAN_BY_USER albu ON albu.id_loan = al.id\n"
            + "    WHERE loan_status = 'APPROVED' \n"
            + "    AND DATE(al.created_on) = DATE(':dateReport')) \n"
            + "    as opening_fee_today,\n"
            + "-- cobranza\n"
            + "(SELECT IF(ISNULL(SUM(ld.payment_amount)),0,SUM(ld.payment_amount)) \n"
            + "FROM APC_LOAN_DETAIL ld\n"
            + "INNER JOIN APC_LOAN l ON l.id = ld.id_loan \n"
            + "INNER JOIN APC_LOAN_BY_USER lbu ON lbu.id_loan = l.id\n"
            + "WHERE lbu.id_user = 'aad0c673-eb93-11ea-b7e1-02907d0fb4e6'  \n"
            + "AND DATE(ld.created_on) = DATE(':dateReport') \n"
            + "AND ld.loan_details_type IN ('PAYMENT','RENOVATION_PAYMENT','TRANSFER')) as cobranza_today,\n"
            + "-- colocacion\n"
            + "(SELECT IF(ISNULL(SUM(alt.payment)),0,SUM(alt.payment)) FROM APC_LOAN al \n"
            + "    INNER JOIN APC_LOAN_TYPE alt ON al.id_loan_type = alt.id \n"
            + "    INNER JOIN APC_LOAN_BY_USER albu ON albu.id_loan = al.id\n"
            + "    WHERE loan_status = 'APPROVED' \n"
            + "    AND DATE(al.created_on) = DATE(':dateReport')) \n"
            + "    as colocation_today\n"
            + "FROM APC_OFFICE u\n"
            + "WHERE u.office_status = 'ENEBLED';";
    
}
