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

import com.arrebol.taxiservicios.beans.admin.*;
import com.arrebol.taxiservicios.beans.TaxiGenericBean;
import com.arrebol.taxiservicios.controller.admin.ClosingDayController;
import com.arrebol.taxiservicios.controller.admin.GenericValidationController;
import com.arrebol.taxiservicios.controller.mutual.MutualClosingDayController;
import com.arrebol.taxiservicios.controller.mutual.TransferMutualController;
import com.arrebol.taxiservicios.controller.system.UserController;
import com.arrebol.taxiservicios.controller.util.DateWrapper;
import com.arrebol.taxiservicios.model.admin.ClosingDay;
import com.arrebol.taxiservicios.model.admin.ClosingDayDetail;
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.MutualClosingDay;
import com.arrebol.taxiservicios.model.mutual.MutualClosingDayDetail;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import java.awt.Font;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 *
 * @author Oscar Vargas
 */
@Named
@ViewScoped
public class MutualAddClosingDayBean extends TaxiGenericBean implements Serializable {

    /**
     * On chane selected user find all totals to be set before save.
     */
    public void onChangeSelectedUser() {
        logger.info("onChangeSelectedUser");
        try {
            if (null != getSelectedUserId()) {
                
                if(!getTransferMutualController().validateTransferMutualPending(getUserController().getById(getSelectedUserId()))){
                showMessage(FacesMessage.SEVERITY_ERROR,
                 "Transferencia Mutual",
                 "El usuario debe aceptar todas sus transferencias de mutual");

                return;
                
                }
                findAllDetails();
            }
        } catch (Exception e) {
            logger.error(e);
            showMessage(FacesMessage.SEVERITY_ERROR,
                    getBundlePropertyFile().getString("cash.daily.cut"),
                    getBundlePropertyFile().getString("cash.daily.cut.search.exception.desc"));
        }
    }

    /**
     *
     */
    public void saveClosingDay() {
        logger.info("saveClosingDay");
        try {

            if(getGenericController().existMutualStableSmallBoxByCurdate(getLoggedUser()))
            {
                showMessage(FacesMessage.SEVERITY_WARN,
                            "Dia cerrado",
                            "No se pueden eliminar más registros porque ya existe un cuadre de caja chica en mutual del día");
                return;
            }
           
           if(!(getTotalToPay().equals(getTotalPaid())))
           {
               if(getComments() == null || getComments().isEmpty()){
                   showMessage(FacesMessage.SEVERITY_WARN,
                            "Comentarios obligatorios",
                            "Si el corte es diferente al esperado los comentarios son obligatorios");
                    return;
               }
               
           }
            MutualClosingDay closingDay = new MutualClosingDay(UUID.randomUUID().toString());

            closingDay.setUser(new User(getSelectedUserId(), ""));
            closingDay.setActiveStatus(BasicType.ENEBLED);
            closingDay.setAmountExpected(new BigDecimal(getTotalToPay()));
            closingDay.setAmountPaid(new BigDecimal(getTotalPaid()));
            closingDay.setComments(getComments());
            closingDay.setCreatedBy(getLoggedUser());
            closingDay.setCreatedOn(DateWrapper.getTodayMXTime());
            closingDay.setLocation(new Location(getLoggedUser().getLocation().getId()));

            getDetails().stream().map(detail -> {
                detail.setId(UUID.randomUUID().toString());
                return detail;
            }).map(detail -> {
                detail.setClosingDay(closingDay);
                return detail;
            }).map(detail -> {
                detail.setCreatedBy(getLoggedUser());
                return detail;
            }).map(detail -> {
                detail.setCreatedOn(DateWrapper.getTodayMXTime());
                return detail;
            }).filter(detail -> (null == detail.getPerson() || null == detail.getPerson().getId())).forEachOrdered(detail -> {
                detail.setPerson(null);
            });

            if (getController().saveMutualClosingDayAndDetails(closingDay, getDetails())) {
                showMessage(FacesMessage.SEVERITY_INFO,
                        getBundlePropertyFile().getString("cash.daily.cut"),
                        getBundlePropertyFile().getString("cash.daily.cut.add.success.desc"));
                setTotalSanctionsIn(null);
                setTotalSanctionsOut(null);
                setTotalToPay(null);
                setTotalPaid(null);
                setUsers(getController().getAllActiveUsers());
                getDetails().clear();

                //imprimir(closingDay);
            } else {
                logger.error("saveClosingDay else error");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        getBundlePropertyFile().getString("cash.daily.cut"),
                        getBundlePropertyFile().getString("cash.daily.cut.add.exception.desc"));
            }
        } catch (Exception e) {
            logger.error(e);
            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("cash.daily.cut"),
                    getBundlePropertyFile().getString("cash.daily.cut.add.exception.desc"));
        }
    }

    public void imprimir(MutualClosingDay closingDay) {
        Document document = new Document(PageSize.LETTER);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            PdfWriter.getInstance(document, baos);
            List<MutualClosingDayDetail> results = new ArrayList<>();
            results = getController().findDetailsFromMutualClosingDayID(new MutualClosingDay(closingDay.getId()));
            User userTmp = getController().getUserById(closingDay.getUser().getId());
            document.open();

            DateFormat formatter = new SimpleDateFormat("dd/MM/yy");

            Paragraph printDate = new Paragraph("Fecha de impresión: " + formatter.format(new Date()), FontFactory.getFont("arial", 10, Font.BOLD, BaseColor.DARK_GRAY));
            printDate.setAlignment(Element.ALIGN_RIGHT);
            document.add(printDate);

            Paragraph title = new Paragraph("Corte del día - Mutual", FontFactory.getFont("arial", 18, Font.BOLD, BaseColor.DARK_GRAY));
            title.setAlignment(Element.ALIGN_CENTER);
            document.add(title);

            String date = formatter.format(closingDay.getCreatedOn());
            document.add(new Paragraph("Fecha de creación: ", FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            document.add(new Paragraph(date, FontFactory.getFont("arial", 8, Font.PLAIN, BaseColor.BLACK)));
            document.add(new Paragraph("Asesor: ", FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            document.add(new Paragraph(userTmp.getPerson().getFirstName() + " " + userTmp.getPerson().getLastName(), FontFactory.getFont("arial", 8, Font.PLAIN, BaseColor.BLACK)));

            document.add(new Paragraph("Monto esperado: ", FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            document.add(new Paragraph("$" + closingDay.getAmountExpected().toString(), FontFactory.getFont("arial", 8, Font.PLAIN, BaseColor.BLACK)));

            document.add(new Paragraph("Monto pagado: ", FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            document.add(new Paragraph("$" + closingDay.getAmountPaid().toString(), FontFactory.getFont("arial", 8, Font.PLAIN, BaseColor.BLACK)));

            document.add(new Paragraph("Comentarios: ", FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            document.add(new Paragraph(closingDay.getComments(), FontFactory.getFont("arial", 8, Font.PLAIN, BaseColor.BLACK)));

            document.add(Chunk.NEWLINE);

            PdfPTable table = new PdfPTable(5);
            table.setTotalWidth(new float[]{60, 60, 170, 60, 100});

            table.setLockedWidth(true);
            PdfPCell cell = new PdfPCell(new Paragraph("Detalles del corte - Mutual",
                    FontFactory.getFont("arial", 10, Font.BOLD, BaseColor.WHITE)));

            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setBackgroundColor(BaseColor.BLUE);
            cell.setColspan(5);
            table.addCell(cell);

            cell = new PdfPCell(new Paragraph("Tipo",
                    FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setColspan(1);
            table.addCell(cell);

            cell = new PdfPCell(new Paragraph("Monto",
                    FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setColspan(1);
            table.addCell(cell);

            cell = new PdfPCell(new Paragraph("Comentarios",
                    FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setColspan(1);
            table.addCell(cell);

            cell = new PdfPCell(new Paragraph("Tipo",
                    FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setColspan(1);
            table.addCell(cell);

            cell = new PdfPCell(new Paragraph("Persona",
                    FontFactory.getFont("arial", 8, Font.BOLD, BaseColor.BLACK)));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setColspan(1);
            table.addCell(cell);

            for (MutualClosingDayDetail tmp : results) {

                cell = new PdfPCell(new Paragraph(tmp.getType(),
                        FontFactory.getFont("arial", 6, Font.PLAIN, BaseColor.BLACK)));
                cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                cell.setColspan(1);
                table.addCell(cell);

                cell = new PdfPCell(new Paragraph(tmp.getAmount() != null ? "$" + tmp.getAmount().toString() : "$0.00",
                        FontFactory.getFont("arial", 6, Font.PLAIN, BaseColor.BLACK)));
                cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                cell.setColspan(1);
                table.addCell(cell);

                cell = new PdfPCell(new Paragraph(tmp.getComments(),
                        FontFactory.getFont("arial", 6, Font.PLAIN, BaseColor.BLACK)));
                cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                cell.setColspan(1);
                table.addCell(cell);

                cell = new PdfPCell(new Paragraph("  ",
                        FontFactory.getFont("arial", 6, Font.PLAIN, BaseColor.BLACK)));
                cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                cell.setColspan(1);
                table.addCell(cell);

                cell = new PdfPCell(new Paragraph(tmp.getPerson() != null ? tmp.getPerson().getFirstName() + " " + tmp.getPerson().getLastName() : "",
                        FontFactory.getFont("arial", 6, Font.PLAIN, BaseColor.BLACK)));
                cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                cell.setColspan(1);
                table.addCell(cell);
            }

            document.add(table);

            document.add(Chunk.NEWLINE);
            document.add(Chunk.NEWLINE);
            document.add(Chunk.NEWLINE);
            document.add(Chunk.NEWLINE);

            document.add(new Paragraph("                  __________________________                 __________________________"));
            document.add(new Paragraph("                                      Firma                                      Nombre y firma cajero responsable"));
            document.add(new Paragraph("                                " + userTmp.getPerson().getFirstName() + " " + userTmp.getPerson().getLastName()));

        } catch (Exception e) {
            System.out.print("Error 1: " + e.getMessage());
        }

        document.close();
        FacesContext context = FacesContext.getCurrentInstance();
        Object response = context.getExternalContext().getResponse();
        if (response instanceof HttpServletResponse) {
            HttpServletResponse hrs = (HttpServletResponse) response;
            hrs.setContentType("application/pdf");
            hrs.setHeader("Content-disposition", "attachment; filename=\"corteDelDia.pdf\"");
            hrs.setContentLength(baos.size());
            try {
                ServletOutputStream out = hrs.getOutputStream();
                baos.writeTo(out);
                out.flush();

            } catch (IOException e) {
                System.out.print("Error 2: " + e.getMessage());
            }
            context.responseComplete();
        }
    }

    /**
     *
     */
    private void findAllDetails() {
        try {

            BigDecimal totalTiempoAire =  getController().findTotalsBigDecimal(query_total_inicios, getSelectedUserId());
            setTotalSanctionsIn(getController().findTotals(query_total_sanctions_in, getSelectedUserId()) + 
                    (totalTiempoAire != null ? Double.parseDouble(totalTiempoAire.toString()) : 0D));

            setTotalSanctionsOut(getController().findTotals(query_total_sanctions_out, getSelectedUserId()));
            
            setTotalSiniestro(getController().findTotals(query_total_transfer_receiver, getSelectedUserId()));
            
            setSaveCashDailyCut(true);
            setDetails(getController().findMutualClosingDayDetails(getSelectedUserId()));
            sumTotals();
        } catch (Exception e) {
            logger.error(e);
            setSaveCashDailyCut(false);
            throw e;
        }
    }

    private void sumTotals() {
        try {
            totalToPay = getTotalSiniestro() + getTotalSanctionsIn() - getTotalSanctionsOut();
        } catch (Exception e) {
            logger.error(e);
            setSaveCashDailyCut(false);
            throw e;
        }
    }

    @PostConstruct
    public void init() {
        logger.info("init");
        try {
            loadBundlePropertyFile();

            setController(new MutualClosingDayController());
            setGenericController(new GenericValidationController());
            setUsers(getController().getAllActiveUsers());
            setTransferMutualController(new TransferMutualController());
            setUserController(new UserController());
            setSaveCashDailyCut(false);

        } catch (Exception e) {
            logger.error(e);
        }
    }

    private MutualClosingDayController controller;
    private GenericValidationController genericController;
    private TransferMutualController transferMutualController;
    private UserController userController;
    private List<User> users;
    private String selectedUserId;
    private Double totalSanctionsIn;
    private Double totalSanctionsOut;
    private Double totalSiniestro;
    private boolean saveCashDailyCut;
    private List<MutualClosingDayDetail> details;
    private String comments;
    private Double totalToPay;
    private Double totalPaid;
    private boolean existSalesToPay;

    public TransferMutualController getTransferMutualController() {
        return transferMutualController;
    }

    public void setTransferMutualController(TransferMutualController transferMutualController) {
        this.transferMutualController = transferMutualController;
    }

    
    
    public Double getTotalSiniestro() {
        return totalSiniestro;
    }

    public void setTotalSiniestro(Double totalSiniestro) {
        this.totalSiniestro = totalSiniestro;
    }

    public GenericValidationController getGenericController() {
        return genericController;
    }

    public void setGenericController(GenericValidationController genericController) {
        this.genericController = genericController;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public String getSelectedUserId() {
        return selectedUserId;
    }

    public void setSelectedUserId(String selectedUserId) {
        this.selectedUserId = selectedUserId;
    }

    public Double getTotalSanctionsIn() {
        if (null == totalSanctionsIn) {
            totalSanctionsIn = 0d;
        }
        return totalSanctionsIn;
    }

    public void setTotalSanctionsIn(Double totalSanctionsIn) {
        this.totalSanctionsIn = totalSanctionsIn;
    }

    public Double getTotalSanctionsOut() {
        if (null == totalSanctionsOut) {
            totalSanctionsOut = 0d;
        }
        return totalSanctionsOut;
    }

    public void setTotalSanctionsOut(Double totalSanctionsOut) {
        this.totalSanctionsOut = totalSanctionsOut;
    }
    
    public boolean getSaveCashDailyCut() {
        return saveCashDailyCut;
    }

    public void setSaveCashDailyCut(boolean saveCashDailyCut) {
        this.saveCashDailyCut = saveCashDailyCut;
    }

    public String getComments() {
        return comments;
    }

    public void setComments(String comments) {
        this.comments = comments;
    }

    public Double getTotalToPay() {
        if (null == totalToPay) {
            totalToPay = 0d;
        }
        return totalToPay;
    }

    public void setTotalToPay(Double totalToPay) {
        this.totalToPay = totalToPay;
    }

    public Double getTotalPaid() {
        return totalPaid;
    }

    public void setTotalPaid(Double totalPaid) {
        if (null == totalPaid) {
            totalPaid = 0d;
        }
        this.totalPaid = totalPaid;
    }

    public boolean isExistSalesToPay() {
        return existSalesToPay;
    }

    public void setExistSalesToPay(boolean existSalesToPay) {
        this.existSalesToPay = existSalesToPay;
    }

    public MutualClosingDayController getController() {
        return controller;
    }

    public void setController(MutualClosingDayController controller) {
        this.controller = controller;
    }

    public List<MutualClosingDayDetail> getDetails() {
        return details;
    }

    public void setDetails(List<MutualClosingDayDetail> details) {
        this.details = details;
    }

    public UserController getUserController() {
        return userController;
    }

    public void setUserController(UserController userController) {
        this.userController = userController;
    }
    

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

    private final String sub_query_to_find_previously_closing_day = "(SELECT DATE(cd.created_on) FROM MUTUAL_CLOSING_DAY cd WHERE DATE(cd.created_on) <= CURDATE() AND cd.user_id = :userID AND cd.active_status = 'ENEBLED' order by cd.created_on DESC LIMIT 1)";
    private final String query_total_sanctions_in = "SELECT IF(ISNULL(SUM(payment)),0, SUM(payment)) AS total_sanctions_in FROM MUTUAL_ADD WHERE DATE(created_on)  > " + sub_query_to_find_previously_closing_day + " AND created_by = :userID";
    private final String query_total_sanctions_out = "SELECT IF(ISNULL(SUM(payment)),0, SUM(payment)) AS total_sanctions_out FROM MUTUAL_OUT WHERE DATE(created_on)  > " + sub_query_to_find_previously_closing_day + " AND created_by = :userID";
    private final String query_total_transfer_receiver = "SELECT IF(ISNULL(SUM(amount_to_transfer)),0, SUM(amount_to_transfer)) AS total_transfer_receiver FROM TRANSFER_MUTUAL WHERE DATE(created_on)  > " + sub_query_to_find_previously_closing_day + "  AND action_status = 'APPROVED' AND active_status = 'ENEBLED' AND id_user_receiver = :userID";
    private final String query_total_inicios = "SELECT IF(ISNULL(SUM(amount)),0, SUM(amount)) AS total_transfer_receiver FROM MUTUAL_INICIOS WHERE DATE(created_on)  > " + sub_query_to_find_previously_closing_day + "  AND active_status = 'ENEBLED' AND user_id = :userID";

}
