package org.gcube.application.cms.usecases.mocks;

import lombok.Data;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.gcube.application.geoportal.common.model.legacy.Concessione;
import org.gcube.application.geoportal.common.model.legacy.InputStreamDescriptor;
import org.gcube.application.geoportal.common.model.rest.AddSectionToConcessioneRequest;
import org.gcube.application.geoportal.common.rest.MongoConcessioni;
import org.gcube.application.geoportal.common.utils.FileSets;
import org.gcube.application.geoportal.common.utils.Files;
import org.gcube.application.geoportal.common.utils.StorageUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import static org.gcube.application.geoportal.client.plugins.GeoportalAbstractPlugin.mongoConcessioni;

@Slf4j
@RequiredArgsConstructor
@ToString
public class ConcessionPublisherThread implements Runnable{



    //Threads
    private static AtomicLong queued=new AtomicLong(0);
    private static AtomicLong completed = new AtomicLong(0);

    //Concessioni
    @Data
    static class Report{
        private ConcurrentLinkedQueue<Concessione> error=new ConcurrentLinkedQueue<>();
        private ConcurrentLinkedQueue<Concessione> success=new ConcurrentLinkedQueue<>();
        private ConcurrentLinkedQueue<Concessione> warning=new ConcurrentLinkedQueue<>();
        private ConcurrentLinkedQueue<String> noReport=new ConcurrentLinkedQueue<>();
    }

    private static ConcessionPublisherThread.Report report=new ConcessionPublisherThread.Report();

    private static ExecutorService exec=Executors.newFixedThreadPool(5);

    public static void submit(ConcessionPublisherThread c){
        log.info("Submitting {}",c);
        exec.submit(c);
        log.info("Submitted {} ",queued.incrementAndGet());
    }

    public static ConcessionPublisherThread.Report waitCompletion(){
        try {
            while (!exec.awaitTermination(2, TimeUnit.MINUTES)) {
                log.info("Waiting .. completed {}, out of {} ",completed.get(),queued.get());
                if(completed.get()==queued.get()) exec.shutdown();
            }
        }catch(InterruptedException e){
            log.info("Process finished");
        }
        return report;
    }

    @NonNull
    private File baseDir;
    @NonNull
    private String positionPath;
    @NonNull
    private String projectName;





    @Override
    public void run() {
        Concessione c=null;
        try {
            MongoConcessioni client=mongoConcessioni().build();
            StorageUtils storage=new StorageUtils();

            //NB raggruppa per file
            Map.Entry<String, List<File>> posSets = Files.getAllShapeSet(new File(baseDir,positionPath),true).
                    entrySet().stream().findFirst().get();
            Map<String, List<File>> pianteSets = Files.getAllShapeSet(new File(baseDir,projectName),true);

            if(pianteSets.size()>1)
                pianteSets.remove(posSets.getKey());



            log.debug("Entry {} pos Size {} piante {} ",projectName,posSets.getValue().size(),pianteSets.size());


             c = createMock(projectName,baseDir.getName(), pianteSets, posSets.getValue(), client, storage);

            switch(c.getReport().getStatus()){
                case PASSED: report.getSuccess().add(c);
                break;
                case ERROR: report.getError().add(c);
                break;
                case WARNING:report.getWarning().add(c);
                break;
            }

        }catch(Throwable t){
            log.error("Problematic entry "+this,t);
            report.getNoReport().add(projectName + baseDir);
        }finally{
            log.info("Completed N {}", completed.incrementAndGet());
        }
    }

   public static AddSectionToConcessioneRequest prepareRequest(StorageUtils storage, String path, File... toUpload) throws FileNotFoundException {
        AddSectionToConcessioneRequest toReturn=new AddSectionToConcessioneRequest();
        toReturn.setDestinationPath(path);

        for (File f : toUpload) {
            if(!f.isDirectory())
                toReturn.getStreams().add(FileSets.asTemp(storage, new InputStreamDescriptor(new FileInputStream(f), f.getName())));
            else {
                toReturn.getStreams().addAll(prepareRequest(storage,path,f.listFiles()).getStreams());
            }
        }
        return toReturn;
    }

    private static Concessione createMock(String baseName, String packageName, Map<String,List<File>> piante, List<File> pos,
                                          MongoConcessioni client, StorageUtils storage) throws Exception {

        return null;

//        Concessione c= TestConcessioniModel.prepareConcessione(piante.size(), 1);
//        c.setNome("Mock for "+baseName+" ("+packageName+")");
//        c= client.createNew(c);
//        String mongoId=c.getMongo_id();
//
//        // TEST DATA, DO NOT CARE
//        client.registerFileSet(mongoId, prepareRequest(storage,
//                Concessione.Paths.RELAZIONE,new File (TestConcessioniModel.getBaseFolder(),"relazione.pdf")));
//
//        client.registerFileSet(mongoId, prepareRequest(storage,
//                Concessione.Paths.imgByIndex(0),Files.getSiblings(TestConcessioniModel.getBaseFolder(),"immagine").get(0)));
//
//        // POSIZIONAMENTO
//
//        client.registerFileSet(mongoId, prepareRequest(storage,
//                Concessione.Paths.POSIZIONAMENTO,pos.toArray(new File[pos.size()])));
//
//        // PIANTE
//        Map.Entry<String,List<File>>[] entries= piante.entrySet().toArray(new Map.Entry[0]);
//        for( int i= 0; i< piante.size();i++) {
//            // Set layer name
//            c=client.getById(mongoId);
//            String path=Concessione.Paths.piantaByIndex(i);
//            c.getContentByPath(path).setTitolo(" Pianta from "+entries[i].getKey());
//            client.update(mongoId, Serialization.write(c));
//
//            //Set fileset
//            client.registerFileSet(mongoId, prepareRequest(storage,path, entries[i].getValue().toArray(new File[0])));
//        }
//
//        c=client.publish(mongoId);
//
//        System.out.println("@@@ Concessione "+c.getNome()+"\t STATUS : "+ c.getReport().getStatus());
//
//        return c;
    }
}
