package com.workfusion.odf.service;

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import com.workfusion.odf.api.domain.Document;
import com.workfusion.odf.api.domain.Transaction;

public class DatastoreSplitJoinService implements SplitJoinService {

    private TransactionService transactionService;
    private Logger log;

    @Inject
    public DatastoreSplitJoinService(TransactionService transactionService, Logger log) {
        this.transactionService = transactionService;
        this.log = log;
    }

    @Override
    public List<Document> splitTransaction(String id) {
        return splitTransaction(id, x -> true);
    }

    @Override
    public List<Document> splitTransactionForOCR(String id) {
        return splitTransaction(id, Document::isOcrDocument);
    }

    @Override
    public List<Document> splitTransaction(String id, Predicate<Document> documentFilter) {
        Transaction transaction = transactionService.byId(id);
        if (transaction != null) {
            List<Document> ocrDocs = transaction.getDocs().stream().filter(documentFilter).collect(Collectors.toList());
            ocrDocs.forEach(doc -> doc.setMerged(false));

            transaction.getDocs().stream().filter(not(documentFilter)).forEach(doc -> doc.setMerged(true));
            transactionService.update(transaction);
            log.debug("Transaction [{}] was split into {} out of {} documents", id, ocrDocs.size(), transaction.getDocs().size());

            return ocrDocs;
        }

        return null; // No transaction
    }

    @Override
    public boolean joinTransaction(String id, String documentId) {
        Transaction transaction = transactionService.byId(id);
        if (transaction != null) {
            List<Document> nonProcessedDocs = transaction.getDocs().stream().filter(doc-> !doc.isMerged()).collect(Collectors.toList());
            nonProcessedDocs.stream().filter(doc -> StringUtils.equals(doc.getId(), documentId)).forEach(document -> document.setMerged(true));
            transactionService.update(transaction);

            boolean joined = nonProcessedDocs.size() <= 1;
            log.debug("Joining document [{}] into transaction [{}]. " +
                    (joined ? "Transaction was joined" : "Transaction is still waiting for other doc"), documentId, id);
            return joined;
        }

        return false; // No transaction
    }

    public static <T> Predicate<T> not(Predicate<T> t) {
        return t.negate();
    }
}
