/* BdfServer_Commands - Copyright (c) 2011-2025 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package fr.exemole.bdfserver.commands.mailing;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.BdfServerConstants;
import fr.exemole.bdfserver.api.interaction.InteractionConstants;
import fr.exemole.bdfserver.api.interaction.domains.MailingDomain;
import fr.exemole.bdfserver.api.users.BdfUser;
import fr.exemole.bdfserver.email.EmailBuffer;
import fr.exemole.bdfserver.email.FicheAttachmentParameters;
import fr.exemole.bdfserver.email.SendEngine;
import fr.exemole.bdfserver.email.SendReport;
import fr.exemole.bdfserver.email.SmtpManager;
import fr.exemole.bdfserver.email.TableExportEmail;
import fr.exemole.bdfserver.tools.exportation.table.TableExportParametersBuilder;
import fr.exemole.bdfserver.tools.instruction.AbstractBdfCommand;
import fr.exemole.bdfserver.tools.instruction.BdfErrors;
import fr.exemole.bdfserver.tools.instruction.RequestHandler;
import fr.exemole.bdfserver.tools.users.BdfUserUtils;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import net.fichotheque.addenda.Version;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.Fiches;
import net.fichotheque.exportation.transformation.TransformationKey;
import net.fichotheque.sphere.Redacteur;
import net.fichotheque.utils.AddendaUtils;
import net.fichotheque.utils.CorpusMetadataUtils;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.request.RequestMap;
import net.mapeadores.util.text.StringUtils;
import net.mapeadores.util.text.ValidExtension;


/**
 *
 * @author Vincent Calame
 */
public class SendCommand extends AbstractBdfCommand {

    public final static String COMMANDNAME = "Send";
    public final static String SELFBCC_PARAMNAME = "selfbcc";
    public final static String TYPE_PARAMNAME = "type";
    public final static String SUBJECT_PARAMNAME = "subject";
    public final static String TO_PARAMNAME = "to";
    public final static String CC_PARAMNAME = "cc";
    public final static String BCC_PARAMNAME = "bcc";
    public final static String MESSAGE_PARAMNAME = "message";
    public final static String DOCUMENTVERSION_PARAMNAME = "documentversion";
    public final static String FICHEVERSION_PARAMNAME = "ficheversion";
    public final static String HTML_FICHEVERSION_PARAMVALUE = "html";
    public final static String ODT_FICHEVERSION_PARAMVALUE = "odt";
    public final static String HTMLTEMPLATE_PARAMNAME = "htmltemplate";
    public final static String ODTTEMPLATE_PARAMNAME = "odttemplate";
    public final static String EXTENSION_PARAMNAME = "extension";
    private SmtpManager smtpManager;
    private EmailBuffer emailBuffer;

    public SendCommand(BdfServer bdfServer, RequestMap requestMap) {
        super(bdfServer, requestMap);
    }

    @Override
    public boolean needSynchronisation() {
        return false;
    }

    @Override
    protected void doCommand() throws ErrorMessageException {
        if (emailBuffer.hasWrongAddresses()) {
            throw BdfErrors.error("_ error.wrong.addresslist");
        }
        SendEngine sendEngine = new SendEngine(smtpManager, this);
        SendReport sendReport = sendEngine.sendEmail(emailBuffer);
        putResultObject(SENDREPORT_OBJ, sendReport);
        switch (sendReport.getState()) {
            case SendReport.OK_STATE:
                setDone(getDoneMessageKey());
                break;
            case SendReport.EMAILBUILD_ERROR_STATE:
                throw BdfErrors.error("_ error.exception.sendreport_emailbuild", sendReport.getErrorMessage());
            case SendReport.SEND_ERROR_STATE:
                throw BdfErrors.error("_ error.exception.sendreport_error", sendReport.getErrorMessage());
        }
    }

    @Override
    protected void checkParameters() throws ErrorMessageException {
        smtpManager = testSmtpManager(bdfServer);
        emailBuffer = buildFromRequest(requestHandler, false);
        if (emailBuffer.getSubject() == null) {
            throw BdfErrors.error("_ error.empty.subject");
        }
        if (emailBuffer.getMessage() == null) {
            throw BdfErrors.error("_ error.empty.message");
        }
        if (emailBuffer.isWithoutField(EmailBuffer.TO_FIELD)) {
            throw BdfErrors.error("_ error.empty.to");
        }
        putResultObject(EMAILBUFFER_OBJ, emailBuffer);
    }

    private String getDoneMessageKey() {
        switch (emailBuffer.getSendType()) {
            case MailingDomain.FICHE_SENDTYPE:
                return "_ done.mailing.send_fiche";
            case MailingDomain.COMPILATION_SENDTYPE:
                return "_ done.mailing.send_compilation";
            case MailingDomain.SELECTION_SENDTYPE:
                return "_ done.mailing.send_selection";
            case MailingDomain.TABLEEXPORT_SENDTYPE:
                return "_ done.mailing.send_tableexport";
            default:
                throw new SwitchException("Unknown sendType: " + emailBuffer.getSendType());
        }
    }

    public static EmailBuffer buildFromRequest(RequestHandler requestHandler, boolean withDefaultValue) throws ErrorMessageException {
        Redacteur redacteur = requestHandler.getBdfUser().getRedacteur();
        String sendType = requestHandler.getMandatoryParameter(TYPE_PARAMNAME);
        EmailBuffer eb;
        switch (sendType) {
            case MailingDomain.FICHE_SENDTYPE:
                eb = initFiche(requestHandler, withDefaultValue);
                break;
            case MailingDomain.COMPILATION_SENDTYPE:
                eb = EmailBuffer.buildForCompilation(requestHandler.getBdfServer(), requestHandler.getBdfUser());
                eb.setFicheAttachmentParameters(initFicheAttachmentParameters(requestHandler, withDefaultValue, TransformationKey.COMPILATION_INSTANCE));
                break;
            case MailingDomain.SELECTION_SENDTYPE:
                eb = initSelection(requestHandler, withDefaultValue);
                break;
            case MailingDomain.TABLEEXPORT_SENDTYPE:
                TableExportInitializer tableExportInitializer = new TableExportInitializer(requestHandler, withDefaultValue);
                eb = tableExportInitializer.init();
                break;
            default:
                throw BdfErrors.unknownParameterValue(TYPE_PARAMNAME, sendType);
        }
        parseAddresses(requestHandler, redacteur, eb, EmailBuffer.TO_FIELD, TO_PARAMNAME);
        parseAddresses(requestHandler, redacteur, eb, EmailBuffer.CC_FIELD, CC_PARAMNAME);
        parseAddresses(requestHandler, redacteur, eb, EmailBuffer.BCC_FIELD, BCC_PARAMNAME);
        eb.setSubject(requestHandler.getTrimedParameter(SUBJECT_PARAMNAME));
        boolean withBcc;
        if (withDefaultValue) {
            withBcc = true;
        } else {
            withBcc = requestHandler.isTrue(SELFBCC_PARAMNAME);
        }
        eb.setWithRedacteurBcc(withBcc);
        eb.setMessage(requestHandler.getTrimedParameter(MESSAGE_PARAMNAME));
        return eb;
    }

    private static void parseAddresses(RequestHandler requestHandler, Redacteur redacteur, EmailBuffer eb, String fieldName, String paramName) throws ErrorMessageException {
        String[] values = requestHandler.getTokens(paramName);
        if (values.length > 0) {
            List<String> valueList = new ArrayList<String>();
            for (String toValue : values) {
                String[] tokens = StringUtils.getTechnicalTokens(toValue, false);
                for (String token : tokens) {
                    valueList.add(token);
                }
            }
            int size = valueList.size();
            if (size > 0) {
                eb.parseToArray(requestHandler.getFichotheque(), fieldName, valueList, redacteur.getSubsetKey());
            }
        }
    }

    private static EmailBuffer initFiche(RequestHandler requestHandler, boolean withDefaultValue) throws ErrorMessageException {
        FicheMeta ficheMeta = requestHandler.getMandatoryFicheMeta();
        requestHandler.checkRead(ficheMeta);
        BdfServer bdfServer = requestHandler.getBdfServer();
        BdfUser bdfUser = requestHandler.getBdfUser();
        EmailBuffer eb = EmailBuffer.buildForFiche(bdfServer, bdfUser, ficheMeta);
        if ((withDefaultValue) && (eb.getSubject() == null)) {
            eb.setSubject(CorpusMetadataUtils.getFicheTitle(ficheMeta, bdfUser.getWorkingLang(), bdfUser.getFormatLocale()));
        }
        eb.setFicheAttachmentParameters(initFicheAttachmentParameters(requestHandler, withDefaultValue, new TransformationKey(ficheMeta.getSubsetKey())));
        return eb;
    }

    private static EmailBuffer initSelection(RequestHandler requestHandler, boolean withDefaultValue) throws ErrorMessageException {
        Set<FicheMeta> ficheMetaSet = new LinkedHashSet<FicheMeta>();
        for (Corpus corpus : requestHandler.getFichotheque().getCorpusList()) {
            String[] param_selection = requestHandler.getTokens("selection_" + corpus.getSubsetName());
            for (String token : param_selection) {
                try {
                    int id = Integer.parseInt(token);
                    FicheMeta ficheMeta = corpus.getFicheMetaById(id);
                    if (ficheMeta != null) {
                        ficheMetaSet.add(ficheMeta);
                    }
                } catch (NumberFormatException nfe) {
                }
            }
        }
        BdfServer bdfServer = requestHandler.getBdfServer();
        BdfUser bdfUser = requestHandler.getBdfUser();
        EmailBuffer eb = EmailBuffer.buildForSelection(bdfServer, bdfUser, ficheMetaSet);
        TransformationKey transformationKey;
        Fiches selectedFiches = bdfUser.getSelectedFiches();
        if (selectedFiches.getEntryList().size() == 1) {
            transformationKey = new TransformationKey(selectedFiches.getEntryList().get(0).getCorpus().getSubsetKey());
        } else {
            transformationKey = null;
        }
        eb.setFicheAttachmentParameters(initFicheAttachmentParameters(requestHandler, withDefaultValue, transformationKey));
        return eb;
    }

    private static FicheAttachmentParameters initFicheAttachmentParameters(RequestHandler requestHandler, boolean withDefaultValue, TransformationKey transformationKey) throws ErrorMessageException {
        FicheAttachmentParameters ficheAttachmentParameters = new FicheAttachmentParameters();
        String[] values = requestHandler.getTokens(FICHEVERSION_PARAMNAME);
        if (values.length > 0) {
            for (String value : values) {
                if (value.equals(HTML_FICHEVERSION_PARAMVALUE)) {
                    ficheAttachmentParameters
                            .setWithHtml(true)
                            .setHtmlTemplateName(requestHandler.getTrimedParameter(HTMLTEMPLATE_PARAMNAME, true));
                } else if (value.equals(ODT_FICHEVERSION_PARAMVALUE)) {
                    ficheAttachmentParameters
                            .setWithOdt(true)
                            .setOdtTemplateName(requestHandler.getParameter(ODTTEMPLATE_PARAMNAME, true));
                }
            }
        } else if (withDefaultValue) {
            ficheAttachmentParameters.setWithHtml(true);
            if (transformationKey != null) {
                ficheAttachmentParameters
                        .setHtmlTemplateName(BdfUserUtils.getSimpleTemplateKey(requestHandler, transformationKey).getName())
                        .setOdtTemplateName(BdfUserUtils.getStreamTemplateKey(requestHandler, transformationKey, ValidExtension.ODT).getName());
            }
        }
        String[] versionArray = requestHandler.getTokens(DOCUMENTVERSION_PARAMNAME);
        for (String versionKey : versionArray) {
            try {
                Version version = AddendaUtils.parseVersionKey(versionKey, requestHandler.getFichotheque());
                ficheAttachmentParameters.addVersion(version);
            } catch (ParseException pe) {

            }
        }
        return ficheAttachmentParameters;
    }

    public static SmtpManager testSmtpManager(BdfServer bdfServer) throws ErrorMessageException {
        SmtpManager smtpManager = (SmtpManager) bdfServer.getContextObject(BdfServerConstants.SMTPMANAGER_CONTEXTOBJECT);
        if (!smtpManager.isInit()) {
            StringBuilder buf = new StringBuilder();
            buf.append("Smtp parameters are not initialized ");
            for (String error : smtpManager.getErrorList()) {
                buf.append(" / ");
                buf.append(error);
            }
            buf.append(")");
            throw BdfErrors.internalError(buf.toString());
        }
        return smtpManager;
    }


    private static class TableExportInitializer {

        private final boolean withDefaultValue;
        private final RequestHandler requestHandler;
        private final TableExportParametersBuilder builder;
        private final String tableExportName;
        private final String storeName;

        private TableExportInitializer(RequestHandler requestHandler, boolean withDefaultValue) {
            requestHandler = RequestHandler.cloneHandler(requestHandler);
            this.withDefaultValue = withDefaultValue;
            this.tableExportName = requestHandler.getTrimedParameter(InteractionConstants.TABLEEXPORT_PARAMNAME);
            this.builder = TableExportParametersBuilder.init()
                    .setTableExportName(tableExportName);
            if (tableExportName == null) {
                storeName = "send_tableexport";
            } else {
                storeName = "send_tableexport_" + tableExportName;
            }
            if (withDefaultValue) {
                requestHandler.setDefaultMap(requestHandler.getStoredValues(storeName));
            }
            this.requestHandler = requestHandler;
        }

        private EmailBuffer init() throws ErrorMessageException {
            Corpus corpus = requestHandler.getMandatoryCorpus();
            if (!requestHandler.getPermissionSummary().hasAccess(corpus)) {
                throw BdfErrors.wrongParameterValue("corpus", corpus.getSubsetName());
            }
            if (!withDefaultValue) {
                requestHandler.enableStore();
            }
            initTableParameters();
            initHeaderType();
            String charset = initCharset();
            String extension = initExtension();
            if (!withDefaultValue) {
                requestHandler.store(storeName);
            }
            return EmailBuffer.buildForTableExport(requestHandler.getBdfServer(), requestHandler.getBdfUser(), new TableExportEmail(builder.toTableExportParameters(), corpus, extension, charset));
        }

        private String initCharset() throws ErrorMessageException {
            String charset = requestHandler.getTrimedParameter(InteractionConstants.CHARSET_PARAMNAME, "UTF-8");
            return charset;
        }

        private String initExtension() throws ErrorMessageException {
            String extension = requestHandler.getTrimedParameter(EXTENSION_PARAMNAME, "csv");
            switch (extension) {
                case "csv":
                case "ods":
                    break;
                default:
                    throw BdfErrors.unknownParameterValue(EXTENSION_PARAMNAME, extension);

            }
            return extension;
        }

        private void initTableParameters() throws ErrorMessageException {
            if (tableExportName == null) {
                builder.setFicheTableParameters(requestHandler.getFicheTableParameters());
            }
        }

        private void initHeaderType() throws ErrorMessageException {
            builder.setHeaderType(requestHandler.getHeaderType());
        }

    }

}
