package com.workfusion.odf.impl.processor;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;

import groovy.lang.Binding;
import org.apache.commons.io.IOUtils;
import org.codejargon.feather.Provides;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.slf4j.Logger;

import com.workfusion.odf.api.domain.Document;
import com.workfusion.odf.api.domain.Transaction;
import com.workfusion.odf.core.Intake;
import com.workfusion.odf.core.Module;
import com.workfusion.odf.impl.converter.html2pdf.RpaPdfReportGenerator;
import com.workfusion.rpa.core.storage.S3Manager;

@ExtendWith(MockitoExtension.class)
public class TransactionReportProcessorTest {
    @Inject
    private TransactionReportProcessor transactionReportProcessor;

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


    @BeforeEach
    public void init() throws IOException {
        s3Manager = Mockito.mock(S3Manager.class);
        logger = Mockito.mock(Logger.class);
        rpaReportGenerator = Mockito.mock(RpaPdfReportGenerator.class);
        params = Mockito.spy(new HashMap<>());
        params.put(TransactionReportProcessor.PARAM_FTL_TEMPLATE_S3_LINK, "https://intake-bucket.wfinst-307-92-db1.workfusion.com/NegativeNewsReport.ftl");
        params.put(TransactionReportProcessor.PARAM_S3_BUCKET, "target_bucket");
        params.put(TransactionReportProcessor.PARAM_S3_FOLDER, "html2pdf");
        Binding binding = new Binding();
        Module testModule = new Module() {
            @Provides
            public S3Manager s3Manager() {
                return s3Manager;
            }

            @Provides
            public Logger logger() {
                return logger;
            }

            @Provides
            public RpaPdfReportGenerator rpaReportGenerator() {
                return rpaReportGenerator;
            }

            @Provides
            @Named("botConfigParams")
            public Map<String, String> params() {
                return params;
            }
        };

        long start = System.currentTimeMillis();
        Intake intake = Intake.init(binding).override(testModule).injectFields(this).get();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

    @Test
    public void transformSuccessTest() throws Exception {
        // given
    	InputStream inputStreamFTL = IOUtils.toInputStream(
  			"<html>" +
   			"<head>" +
   			"<body>" +
   			"<h1>Negative News Analysis</h1>" +
   			"<div>Entity=${transaction.getAttribute(\"entityName\")}</div>" +
   			"<div>${transaction.getAttribute(\"dateOfInvestigation\")}</div>" +
   			"<h2>1 Summary</h2>" +
   			"<div>Overall Recommendation=${transaction.getAttribute(\"overallRecommendation\")}</div>" +
   			"<div>Negative News Articles=${transaction.getAttribute(\"articlesReviewed\")} of ${transaction.docs?size} (${100 * transaction.getAttribute(\"articlesReviewed\")?number / transaction.docs?size}%)</div>" +
   			"<div>Search Terms:" +
   			"<#assign searchTermsList = transaction.getAttribute(\"suggestedKeywords\")?eval/>" +
   			"<#if (searchTermsList??) && (searchTermsList?size != 0)>" +
   			"<ul>" +
   			"<#list searchTermsList as searchTerm>" +
   			"<li>${searchTerm}</li>" +
   			"</#list>" +
   			"</ul>" +
   			"</#if>" +
   			"</div>" +
   			"</body>" +
   			"</html>",
   			"UTF-8");
        Mockito.when(s3Manager.getFile(ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(inputStreamFTL);
        Mockito.when(s3Manager.uploadFileToS3(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn("https://intake-bucket.wfinst-307-db1.workfusion.com/07a45d38-b61c-4a40-92f6-23a01dd2cd3a.html");

        Transaction transaction = getTransactionMock();

        // when
        Transaction transformedTransaction = transactionReportProcessor.transform(transaction);

        // then
        String htmlReport = params.get(TransactionReportProcessor.PARAM_HTML_REPORT);
        System.out.println("> HTML report:\n" + htmlReport);
        int iEntity = htmlReport.indexOf("Entity=");
        Assertions.assertTrue(htmlReport.indexOf("Arcandor", iEntity) == (iEntity + 7));
        //
        int iOverallRecommendation = htmlReport.indexOf("Overall Recommendation=");
        Assertions.assertTrue(htmlReport.indexOf("Suspicious - Investigate Further", iOverallRecommendation) == (iOverallRecommendation + 23));
        //
        int iNegativeNewsArticles = htmlReport.indexOf("Negative News Articles=");
        Assertions.assertTrue(htmlReport.indexOf("1 of 2 (50%)", iNegativeNewsArticles) == (iNegativeNewsArticles + 23));

        String targetBucket = params.get(TransactionReportProcessor.PARAM_S3_BUCKET);
        String targetFolder = params.get(TransactionReportProcessor.PARAM_S3_FOLDER);
        Mockito.verify(s3Manager, Mockito.times(1)).getFile(ArgumentMatchers.eq(targetBucket), ArgumentMatchers.any());
        Mockito.verify(s3Manager, Mockito.times(1)).uploadFileToS3(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any());
        Mockito.verify(rpaReportGenerator, Mockito.times(1)).generatePdfAndUploadToS3(ArgumentMatchers.any(), ArgumentMatchers.eq(targetBucket), ArgumentMatchers.eq(targetFolder));
    }

    private Transaction getTransactionMock() throws Exception {
        Transaction transaction = new Transaction();
        transaction.setId("1");
        transaction.putAttribute("entityName", "Arcandor");
        transaction.putAttribute("dateOfInvestigation", "September 24, 2018");
        transaction.putAttribute("workerName", "Kyle Hoback, kyle@workfusion.com");
        transaction.putAttribute("overallRecommendation", "Suspicious - Investigate Further");
        transaction.putAttribute("articlesReviewed", "1");
        transaction.putAttribute("suggestedKeywords", "[\"Arcandor AND FRAUD OR MONEY LAUNDERING OR LAUNDERING OR TRAFFICKING OR DRUGS OR ARREST OR SMUGGLING OR BRIBERY OR TERRORISM OR TERRORIST OR EMBEZZLEMENT\"]");
        transaction.putAttribute("highRiskCountriesRelations", "[\"Costa Rica\",\"Macau\",\"Peru\"]");
        transaction.putAttribute("manualTaskLink", "https://demo-spa852.workfusion.com/workfusion/secure/business-process/edit/0a49ebc9-0a59-4567-bc2b-3f90fef5e2f6?actTab=WORKFLOW_DESIGNER");

        List<Document> docs = new ArrayList<>();

        Document doc1 = new Document();
        doc1.setId("2");
        doc1.putAttribute("title", "Former Sal. Oppenheim senior bankers found guilty of fraud");
        doc1.putAttribute("publishingDate", "09 Jul 2015");
        doc1.putAttribute("classificationModelScore", "0.43");
        doc1.putAttribute("triggeredCountries", "[\"Costa Rica\",\"Macau\",\"Peru\"]");
        doc1.putAttribute("suspiciousPhrases", "[\"retail group Arcandor which later went bankrupt\"]");
        doc1.setOriginalDocumentLink("https://42.tut.by/619932");
        docs.add(doc1);

        Document doc2 = new Document();
        doc2.setId("3");
        doc2.putAttribute("title", "Former Bertelsmann CEO sent directly to jail after embezzlement conviction");
        doc2.putAttribute("publishingDate", "14 Nov 2014");
        doc2.putAttribute("classificationModelScore", "0.14");
        doc2.putAttribute("triggeredCountries", "[\"Peru\",\"Macau\"]");
        doc2.putAttribute("suspiciousPhrases", "[\"Misappropriate-ed company funds\"]");
        doc2.setOriginalDocumentLink("https://42.tut.by/619762");
        docs.add(doc2);

        transaction.setDocs(docs);

        return transaction;
    }
}
