package com.workfusion.odf.impl.processor;

import java.io.CharArrayReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
import javax.inject.Named;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.http.MediaType;

import com.workfusion.odf.api.domain.Transaction;
import com.workfusion.odf.impl.converter.html2pdf.RpaPdfReportGenerator;
import com.workfusion.odf.processor.TransactionProcessor;
import com.workfusion.rpa.core.storage.S3Manager;

/**
 * Transaction report processor.
 * May be used for example to generate the "Negative News Report".
 *
 * @author Andrei Urbanovich
 */
public class TransactionReportProcessor implements TransactionProcessor {
    public static final String PARAM_S3_BUCKET = "s3_bucket";

    public static final String PARAM_S3_FOLDER = "s3_folder";

    /** Processor parameter: S3 link to FTL template. Full URL. */
    public static final String PARAM_FTL_TEMPLATE_S3_LINK = "ftl_template_s3_link";

    /** Processor parameter: S3 link to HTML report (FTL generation result). */
    public static final String PARAM_HTML_REPORT_S3_LINK = "html_report_s3_link";

    /** Processor parameter: HTML report (FTL generation result). */
    public static final String PARAM_HTML_REPORT = "html_report";

    /** Processor parameter: S3 link to PDF report. */
    public static final String PARAM_PDF_REPORT_S3_LINK = "pdf_report_s3_link";

    private S3Manager s3Manager;
    private RpaPdfReportGenerator rpaReportGenerator;
    private Map<String, String> params;
    private Logger logger;

    @Inject
    public TransactionReportProcessor(final S3Manager s3Manager, final Logger logger, final RpaPdfReportGenerator rpaReportGenerator,
    		final @Named("botConfigParams") Map<String, String> params) {
    	this.s3Manager = s3Manager;
    	this.logger = logger;
        this.rpaReportGenerator = rpaReportGenerator;
        this.params = params;
    }

    @Override
    public Transaction transform(final Transaction transaction) {
        String targetBucket = params.get(PARAM_S3_BUCKET);
        String targetFolder = params.get(PARAM_S3_FOLDER);
        String ftlTemplateS3Link = params.get(PARAM_FTL_TEMPLATE_S3_LINK);

        try {
            logger.debug("Get FTL template '{}' from S3", ftlTemplateS3Link);

            InputStream isTemplateBody = s3Manager.getFile(targetBucket, ftlTemplateS3Link);
            char[] templateBodyChars = IOUtils.toCharArray(isTemplateBody, Charset.defaultCharset());

            // 1. Generate html report
            String htmlReport = generateHtmlReport(transaction, templateBodyChars);

            // Put HTML report body - to params
            params.put(PARAM_HTML_REPORT, htmlReport);

            // Put HTML report on S3
            String htmlReportFileName = generateHtmlReportFileName();
            logger.debug("Put HTML report on S3: {}", htmlReportFileName);
            String htmlReportS3Link = s3Manager.uploadFileToS3(htmlReport.getBytes("UTF-8"), htmlReportFileName, MediaType.TEXT_HTML_VALUE);
            String pdfReportS3Link = rpaReportGenerator.generatePdfAndUploadToS3(htmlReportS3Link, targetBucket, targetFolder);
            logger.debug("Put PDF report on S3: {}", pdfReportS3Link);

        	transaction.putAttribute(PARAM_PDF_REPORT_S3_LINK, pdfReportS3Link);
        } catch (IOException ex) {
        	throw new RuntimeException("FTL template creation error", ex);
        } catch (TemplateException ex) {
        	throw new RuntimeException("FTL template generation error", ex);
        }

        return transaction;
    }

    private String generateHtmlReport(Transaction transaction, char[] templateBodyChars) throws IOException, TemplateException {
        Map<String, Object> model = new HashMap<>();
        model.put("transaction", transaction);

        Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
        cfg.setObjectWrapper(new DefaultObjectWrapper());
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        Template ftlTemplate = new Template("templateName", new CharArrayReader(templateBodyChars), cfg);
        Writer out = new StringWriter();
        ftlTemplate.process(model, out);
        return out.toString();
    }

    private String generateHtmlReportFileName() {
        StringBuilder fileName = new StringBuilder();
        String s3Folder = params.get(PARAM_S3_FOLDER);
        if (StringUtils.isNotEmpty(s3Folder)) {
            fileName.append(s3Folder).append("/");
        }
        fileName.append("html_report_").append(UUID.randomUUID().toString()).append(".html");

        return fileName.toString();
    }
}
