package com.workfusion.odf.impl.processor.extractor;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.stubbing.Answer;
import org.slf4j.Logger;

import com.workfusion.odf.api.domain.Document;
import com.workfusion.odf.api.domain.Transaction;
import com.workfusion.rpa.core.storage.S3Manager;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class EmlFlatMapProcessorTest {

    private S3Manager s3Manager;
    private EmlFlatMapProcessor mapProcessor;

    @BeforeEach
    void setUp() {
        s3Manager = mock(S3Manager.class);
        mapProcessor = new EmlFlatMapProcessor(s3Manager, mock(Logger.class));
    }

    @Test
    void shouldTransformMailDocument() throws Exception {
        // given
        when(s3Manager.getContent("mail-link.eml")).thenReturn(getMailWithAttachmentData());

        when(s3Manager.uploadFileToS3(any(), any(), any())).thenAnswer(
                (Answer<String>) invocation -> (String) invocation.getArguments()[1]);

        Transaction transaction = createTransaction("mail-link.eml");

        // when
        Transaction transformed = mapProcessor.transform(transaction);

        // then
        List<Document> actualDocuments = transformed.getDocs();
        assertEquals(4, actualDocuments.size());

        actualDocuments.stream().map(Document::getOriginalDocumentLink).forEach(actualS3Link -> {
            assertTrue(StringUtils.isNotEmpty(actualS3Link));
            assertTrue(actualS3Link.startsWith("eml_flatMap"));
            assertTrue(!actualS3Link.contains(".") || actualS3Link.endsWith(".html"));
        });
    }

    private Transaction createTransaction(String docLink) {
        Document document = new Document();
        document.setOriginalDocumentLink(docLink);

        Transaction transaction = new Transaction();
        transaction.setId(UUID.randomUUID().toString());

        List<Document> documents = new ArrayList<>();
        documents.add(document);
        transaction.setDocs(documents);

        return transaction;
    }

    private byte[] getMailWithAttachmentData() throws IOException {
        String mailFilePath = "mail/mail-with-attachments.eml";
        URL mailUrl = EmlFlatMapProcessorTest.class.getClassLoader().getResource(mailFilePath);
        if (mailUrl == null) {
            throw new NullPointerException(String.format("Unable to find: %s", mailFilePath));
        }
        return downloadFromUrl(mailUrl);
    }

    private static byte[] downloadFromUrl(URL url) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
             InputStream inputStream = url.openStream()) {
            byte[] chunk = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(chunk)) > 0) {
                outputStream.write(chunk, 0, bytesRead);
            }
            return outputStream.toByteArray();
        }
    }

}
