package com.alexanderlogistics.mahnlauf;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.ejb.EJB;
import javax.inject.Inject;

import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.Model;
import org.imixs.workflow.SignalAdapter;
import org.imixs.workflow.engine.ModelService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException;

import com.alexanderlogistics.InvoiceUtil;

/**
 * The MahnlaufExecuteAdapter triggers the event 300 for all linked invoices
 * <p>
 * The Adapter also creates a child item '_invoices' with the details of the
 * processed invoices. This item is used in the Workflow Model to construct a
 * HTML Table wen sending the mail.
 * <p>
 * The Adapter also splits the item 'dbtr.mail' into a multi value field if 
 * the value contains email addresses separated with new lines.
 * 
 * 
 * @version 1.0
 * @author rsoika
 */
public class MahnlaufExecuteAdapter implements SignalAdapter {

    @SuppressWarnings("unused")
    private static Logger logger = Logger.getLogger(MahnlaufExecuteAdapter.class.getName());

    @EJB
    ModelService modelService;

    @EJB
    WorkflowService workflowService = null;

    @Inject
    MahnlaufService mahnlaufService;

    /**
     * This method finds all invices ($workitemref) and tirgges event 300
     * 
     * @throws PluginException
     */
    @SuppressWarnings("unchecked")
    @Override
    public ItemCollection execute(ItemCollection mahnLaufWorkitem, ItemCollection event)
            throws AdapterException, PluginException {

        if (mahnLaufWorkitem.isItemEmpty("$workitemref")) {
            throw new PluginException(MahnlaufRefAddAdapter.class.getName(), MahnlaufService.ERROR_WORKFLOW,
                    "Es wurden keine Rechnungen ausgewählt. Der Mahnlauf kann nicht gestartet werden.");
        }

        // get all Invoices of this Mahnlauf
        List<Map<String, List<Object>>> invoiceList = new ArrayList<Map<String, List<Object>>>();
        List<String> refList = mahnLaufWorkitem.getItemValue("$workitemref");

        // sind die Wärhungen idendtisch (mischmasch geht niht)
        String lastCurrency = "";
        for (String uniqueId : refList) {
            ItemCollection invoice = workflowService.getWorkItem(uniqueId);
            String invoiceCurrency = invoice.getItemValueString("invoice.currency");
            if (lastCurrency.isEmpty()) {
                lastCurrency = invoiceCurrency;
            } else {
                if (!lastCurrency.equals(invoiceCurrency)) {
                    throw new PluginException(MahnlaufRefAddAdapter.class.getName(), MahnlaufService.ERROR_WORKFLOW,
                            "In einem Mahnlauf können nur Rechnungen mit der selben Währung ausgewählt werden.");
                }
            }
        }

        double saldo = 0;
        int dunningLevel = 0;
        String currency = "";
        for (String uniqueId : refList) {
            ItemCollection invoice = workflowService.getWorkItem(uniqueId);
            if (invoice != null && (invoice.getTaskID() >= MahnlaufService.TASK_MAHNLAUF_START
                    && invoice.getTaskID() <= MahnlaufService.TASK_MAHNLAUF_END)) {

                // set new invoice.reminder date only if we in due
                if (isInDue(invoice)) {
                    try {
                        // first fetch the event of the invoice to be processed
                        Model invoiceModel;
                        invoiceModel = this.modelService.getModel(invoice.getModelVersion());
                        ItemCollection invoiceEvent = invoiceModel.getEvent(invoice.getTaskID(),
                                MahnlaufService.EVENT_MAHNLAUF_EXECUTE);
                        if (invoiceEvent != null) {
                            ItemCollection eventDunningConfig = this.workflowService.evalWorkflowResult(invoiceEvent,
                                    "dunning", invoice);
                            int period = eventDunningConfig.getItemValueInteger("period");
                            Calendar cal = Calendar.getInstance();
                            cal.setTime(new Date());
                            cal.add(Calendar.DATE, period);
                            cal.set(Calendar.HOUR,0);
                            cal.set(Calendar.MINUTE,0);
                            cal.set(Calendar.SECOND,0);
                            invoice.setItemValue("invoice.reminder", cal.getTime());
                        }

                    } catch (ModelException e) {
                        e.printStackTrace();
                    }
                    mahnlaufService.processInvoice(invoice.event(MahnlaufService.EVENT_MAHNLAUF_EXECUTE));
                }

                switch (invoice.getTaskID()) {
                case 5200:
                case 5201:
                    if (dunningLevel < 1)
                        dunningLevel = 1;
                    break;
                case 5210:
                case 5211:
                    if (dunningLevel < 2)
                        dunningLevel = 2;
                    break;
                case 5220:
                    if (dunningLevel < 3)
                        dunningLevel = 3;
                    break;
                default:
                    if (dunningLevel < 1)
                        dunningLevel = 1;
                    break;
                }

                // create a workitem stub for the mail message
                ItemCollection invoiceStub = new ItemCollection();
                invoiceStub.setItemValue("invoice.number", invoice.getItemValue("invoice.number"));
                invoiceStub.setItemValue("invoice.total", invoice.getItemValue("invoice.total"));
                invoiceStub.setItemValue("invoice.saldo", invoice.getItemValue("invoice.saldo"));
                invoiceStub.setItemValue("invoice.currency", invoice.getItemValue("invoice.currency"));
                invoiceStub.setItemValue("invoice.date", invoice.getItemValue("invoice.date"));
                invoiceStub.setItemValue("invoice.duedate", invoice.getItemValue("invoice.duedate"));
                invoiceStub.setItemValue("$workflowstatus", invoice.getItemValue("$workflowstatus"));
                // test if we have a international status translation..
                if (!invoice.getItemValueString("workflowstatus_en").isEmpty()) {
                    invoiceStub.setItemValue("workflowstatus_en", invoice.getItemValue("workflowstatus_en"));
                } else {
                    // default
                    invoiceStub.setItemValue("workflowstatus_en", invoice.getItemValue("$workflowstatus"));
                }
                invoiceList.add(invoiceStub.getAllItems());

                // store currency in mahnlauf
                currency = invoice.getItemValueString("invoice.currency");

                saldo = saldo + invoice.getItemValueDouble("invoice.saldo");
            }

        }

        mahnLaufWorkitem.setItemValue("dunning.details", invoiceList);
        mahnLaufWorkitem.setItemValue("dunning.saldo", saldo);
        mahnLaufWorkitem.setItemValue("dunning.currency", currency);
        mahnLaufWorkitem.setItemValue("dunning.level", dunningLevel);

        // compute subject
        switch (dunningLevel) {

        case 2:
            mahnLaufWorkitem.setItemValue("mail.subject_de", "2. MAHNUNG");
            mahnLaufWorkitem.setItemValue("mail.subject_en", "2. REMINDER");
            break;
        case 3:
            mahnLaufWorkitem.setItemValue("mail.subject_de", "LETZTE AUSSERGERICHTLICHE MAHNUNG");
            mahnLaufWorkitem.setItemValue("mail.subject_en", "LAST REMINDER");
            break;
        default:
            mahnLaufWorkitem.setItemValue("mail.subject_de", "1. MAHNUNG");
            mahnLaufWorkitem.setItemValue("mail.subject_en", "1. REMINDER");
            break;
        }


        // Verify the dbtr.mail item (split into multi value)
        List<String> mailListe =mahnLaufWorkitem.getItemValue("dbtr.mail");
        for (String mail: mailListe) {
            logger.info(" teste mail:'" + mail + "'");
            if (!InvoiceUtil.validateEmail(mail)) {
                throw new PluginException(MahnlaufExecuteAdapter.class.getName(),
                        "INVALID_EMAIL", "Die Daten konnten nicht aktualisiert werden! Bitte geben Sie eine gültige E-Mail Adresse ein!");		    
            }	
        }
        return mahnLaufWorkitem;
    }

    /**
     * Returns true if the reminder date is today or in the past
     * 
     * @param uniqueid
     * @return
     */
    public boolean isInDue(ItemCollection invoice) {
        LocalDate date = invoice.getItemValueLocalDate("invoice.reminder");
        return date.compareTo(LocalDate.now()) <= 0;
    }

}
