package com.bcxin.signature.components.impls;

import com.bcxin.backend.core.edis.EDIConstants;
import com.bcxin.signature.components.DocumentPushProvider;
import com.bcxin.signature.components.JTLZPendingQueueComponent;
import com.bcxin.signature.components.JTLZPushComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Component
public class DocumentPushProviderImpl implements DocumentPushProvider {
    private static final Logger logger = LoggerFactory.getLogger(DocumentPushProvider.class);
    private final JTLZPendingQueueComponent pendingQueueComponent;
    private final JTLZPushComponent jtlzPushComponent;
    private final ThreadPoolTaskExecutor taskExecutor;

    public DocumentPushProviderImpl(JTLZPendingQueueComponent pendingQueueComponent,
                                    JTLZPushComponent jtlzPushComponent,
                                    ThreadPoolTaskExecutor taskExecutor) {
        this.pendingQueueComponent = pendingQueueComponent;
        this.jtlzPushComponent = jtlzPushComponent;
        this.taskExecutor = taskExecutor;
    }

    @Override
    public void push(DocumentType documentType) {
        String filePrefixMeta = EDIConstants.PUSH_IN_FILE_PREFIX_META_ZGZ;
        if (documentType == DocumentPushProvider.DocumentType.Document) {
            filePrefixMeta = EDIConstants.PUSH_IN_FILE_PREFIX_META_DOCUMENT;
        }

        this.execute(filePrefixMeta, false);
    }

    @Override
    public void cancel_push() {
        this.execute(EDIConstants.PUSH_IN_JTLZ_FZ_PREFIX_META, true);
    }

    protected void executeMetaFile(String traceId, Collection<String> pendingFileNames){
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        boolean isEmpty = false;
        logger.error("{} prepare to process the pendingFileNames:{}", traceId, isEmpty, pendingFileNames.size());
        Exception lastException = null;
        try {
            List<CompletableFuture> resultFutures =
                    pendingFileNames.stream().map(rfn -> {
                        return CompletableFuture.runAsync(() -> {
                            this.jtlzPushComponent.execute(traceId, rfn);
                        }, this.taskExecutor);
                    }).collect(Collectors.toList());

            Object rt = CompletableFuture.allOf(resultFutures.toArray(new CompletableFuture[resultFutures.size()])).join();
            logger.error("success:{}", rt);
        } catch (Exception ex) {
            lastException = ex;
        } finally {
            stopWatch.stop();
            logger.error("{}-({}) Done for signatureJTLZ cost {} seconds - pendingFileSize={}",
                    traceId,
                    (lastException == null ? "SUCCESS" : "ERROR"),
                    stopWatch.getTotalTimeSeconds(), pendingFileNames.size()
            );
        }
    }

    protected void execute(String filePrefix,boolean isFz){
        String traceId = UUID.randomUUID().toString();
        Collection<String> pendingFileNames = null;
        StopWatch metaStopWatch = new StopWatch();
        Exception topException = null;
        try {
            metaStopWatch.start();
            pendingFileNames = pendingQueueComponent.getMetaFilesWithPrefix(filePrefix, 20);
        } catch (Exception ex) {
            topException = ex;
        } finally {
            metaStopWatch.stop();
            logger.error("{} geting pending files-{}:{}; cost {} seconds",
                    traceId,
                    filePrefix,
                    pendingFileNames == null ? "EMPTY" :
                            pendingFileNames.size(),
                    metaStopWatch.getTotalTimeSeconds(), topException);
        }

        if (true) {
            Collection<String> directlyFiles = new ArrayList<>();
            if (!isFz) {
                directlyFiles = pendingQueueComponent.getPendingContentFiles(EDIConstants.PUSH_IN_FILE_PREFIX);
            } else {
                directlyFiles = pendingQueueComponent.getPendingContentFiles(EDIConstants.PUSH_IN_FZ_FILE_PREFIX);
            }

            if(directlyFiles==null) {
                directlyFiles = new ArrayList<>();
            }

            Exception exception = null;
            StopWatch watch = new StopWatch();
            watch.start();
            try {
                this.jtlzPushComponent.execute(traceId, directlyFiles.toArray(new String[directlyFiles.size()]), isFz);
            } catch (Exception ex) {
                exception = ex;
            } finally {
                watch.stop();
                logger.error("{}-Done for directly execute cost {} seconds[pendingFileNames={}] size={}",
                        (exception == null ? "SUCCESS" : "ERROR"),
                        watch.getTotalTimeSeconds(),
                        (CollectionUtils.isEmpty(pendingFileNames) ? "Empty" : pendingFileNames.stream().collect(Collectors.joining(","))),
                        (directlyFiles == null ? "EMPTY" : directlyFiles.size()),
                        exception);
            }

            if (CollectionUtils.isEmpty(pendingFileNames)) {
                return;
            }
        }

        executeMetaFile(traceId, pendingFileNames);
    }
}
