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

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.inject.Inject;

import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;

import com.workfusion.odf.api.domain.Document;
import com.workfusion.odf.impl.converter.extractor.AbstractRecursiveExtractor;
import com.workfusion.odf.impl.converter.extractor.DataWrapper;
import com.workfusion.odf.impl.s3.S3Uploader;
import com.workfusion.odf.processor.DocumentConverter;
import com.workfusion.rpa.core.storage.S3Manager;

public abstract class AbstractFlatMapper extends DocumentConverter {

    protected final S3Manager s3Manager;
    protected final Logger logger;

    @Inject
    public AbstractFlatMapper(final S3Manager s3Manager, final Logger logger) {
        this.s3Manager = s3Manager;
        this.logger = logger;
    }

    protected abstract AbstractRecursiveExtractor getRecursiveExtractor();

    protected abstract String getS3Folder();

    @Override
    protected Set<Document> convertDocument(final Document convertedDocument) {
        String originalDocumentLink = convertedDocument.getOriginalDocumentLink();
        byte[] originalDocumentData = s3Manager.getContent(originalDocumentLink);
        List<DataWrapper> recursiveData = getRecursiveExtractor().recursiveExtract(originalDocumentData, FilenameUtils.getName(originalDocumentLink));

        return getDocumentsRecursive(convertedDocument, recursiveData);
    }

    private Set<Document> getDocumentsRecursive(final Document convertedDocument, final List<DataWrapper> dataWrapperList) {
        Set<Document> documents;
        if (dataWrapperList.isEmpty()) {
            documents = new HashSet<>(1);
            Document convertedDocumentCopy = convertedDocument.createChildDocument();
            convertedDocumentCopy.setId(UUID.randomUUID().toString());
            documents.add(convertedDocumentCopy);
        } else {
            documents = dataWrapperList
                    .stream()
                    .map(dataWrapper -> createDocumentFromDataWrapper(convertedDocument, dataWrapper))
                    .collect(Collectors.toSet());
        }

        return documents;
    }

    private Document createDocumentFromDataWrapper(final Document convertedDocument, final DataWrapper dataWrapper) {
        String uploadedDocLink = getS3Uploader().upload(dataWrapper);

        Document document = convertedDocument.createChildDocument();
        document.setOriginalDocumentLink(uploadedDocLink);
        document.setName(dataWrapper.getName());
        document.setId(UUID.randomUUID().toString());
        document.setType(dataWrapper.getType());
        dataWrapper.getAttributes().forEach(document::putAttribute);

        return document;
    }

    private S3Uploader getS3Uploader() {
        return new S3Uploader(s3Manager, logger, getS3Folder());
    }

}
