package org.gcube.application.geoportal.service.engine.caches;

import com.mongodb.MongoWaitQueueFullException;
import lombok.extern.slf4j.Slf4j;
import org.gcube.application.cms.implementations.ImplementationProvider;
import org.gcube.application.cms.tests.Tests;
import org.gcube.application.cms.tests.TokenSetter;
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
import org.gcube.application.geoportal.common.utils.StorageUtils;
import org.gcube.application.geoportal.common.utils.tests.GCubeTest;
import org.gcube.application.geoportal.service.BasicServiceTestUnit;
import org.junit.Test;

import java.io.File;
import java.io.FileNotFoundException;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;

@Slf4j
public class Caches extends BasicServiceTestUnit {

    @Test
    public void testCache() throws ConfigurationException {
        assumeTrue(GCubeTest.isTestInfrastructureEnabled());
        TokenSetter.set(GCubeTest.getContext());

        Duration ttl=Duration.of(10, ChronoUnit.SECONDS);

        Duration monitorWindow=Duration.of(100, ChronoUnit.SECONDS);

        DummyCache cache= new DummyCache();
        cache.setTTL(ttl);


        Instant startMonitoring=Instant.now();

        LocalDateTime previous=cache.getObject();
        while(Duration.between(startMonitoring,Instant.now()).compareTo(monitorWindow)<0){
            LocalDateTime obj= cache.getObject();
            if(obj.equals(previous)){
                //objects are equals, TTL should be valid
                // Assert : now-creationTime < TTL
                assertTrue(Duration.between(obj,LocalDateTime.now()).compareTo(ttl)<0);
            }else {
                // different object only after TTL
                // Assert : now-creationTime < TTL
                assertTrue(Duration.between(obj,LocalDateTime.now()).compareTo(ttl)<0);
                // Assert : now-previous.creationTime > TTL
                assertTrue(Duration.between(previous,LocalDateTime.now()).compareTo(ttl)>0);
            }
            previous=obj;
            try {
                Thread.sleep(ttl.abs().dividedBy(2).toMillis());
            } catch (InterruptedException e) {
            }
        }
    }


//    @Test
//    public void mongoconnections() throws ConfigurationException, InterruptedException {
//        assumeTrue(GCubeTest.isTestInfrastructureEnabled());
//        TokenSetter.set(GCubeTest.getContext());
//        ExecutorService service = Executors.newFixedThreadPool(1000);
//        LocalDateTime start=LocalDateTime.now();
//        AtomicLong executed = new AtomicLong(0);
//        AtomicLong launched = new AtomicLong(0);
//        //for 100 secs
//        while(Duration.between(start,LocalDateTime.now()).
//                compareTo(Duration.of(100, ChronoUnit.SECONDS))<0){
//            service.execute(new Runnable() {
//                @Override
//                public void run() {
//                    try {
//                        new ConcessioniMongoManager().list();
//                    } catch (ConfigurationException e) {
//                        e.printStackTrace();
//                    } catch (MongoWaitQueueFullException e) {
//                       log.info("Too many connections... ");
//                    }finally{
//                     executed.incrementAndGet();
//                        try {Thread.sleep(500);} catch (InterruptedException i) {}
//                    }
//                }
//            });
//            launched.incrementAndGet();
//        }
//
//        while (!service.awaitTermination(2, TimeUnit.MINUTES)) {
//            log.info("Waiting .. completed {}, out of {} ",executed.get(),launched.get());
//            if(executed.get()==launched.get()) service.shutdown();
//        }
//    }


    //@Test
    public void testStorageCache() throws ConfigurationException, FileNotFoundException, InterruptedException {
        assumeTrue(GCubeTest.isTestInfrastructureEnabled());
        TokenSetter.set(GCubeTest.getContext());
        ExecutorService service = Executors.newFixedThreadPool(10);
        LocalDateTime start=LocalDateTime.now();
        AtomicLong executed = new AtomicLong(0);
        AtomicLong launched = new AtomicLong(0);

        final StorageUtils storage=ImplementationProvider.get().getProvidedObjectByClass(StorageUtils.class);

        String id =storage.putOntoStorage(new File(Tests.FOLDER_CONCESSIONI,"relazione.pdf"))[0].getId();

        //for 100 secs
        while(Duration.between(start,LocalDateTime.now()).
                compareTo(Duration.of(100, ChronoUnit.SECONDS))<0){
            service.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        try {Thread.sleep(1000);} catch (InterruptedException i) {}
                        System.out.println(storage.getURL(id));
//                        storage.getURL(id);
                    } catch (MongoWaitQueueFullException e) {
                        log.info("Too many connections... ");
                    }finally{
                        executed.incrementAndGet();
                        try {Thread.sleep(500);} catch (InterruptedException i) {}
                    }
                }
            });
            launched.incrementAndGet();
        }

        while (!service.awaitTermination(2, TimeUnit.MINUTES)) {
            log.info("Waiting .. completed {}, out of {} ",executed.get(),launched.get());
            if(executed.get()==launched.get()) service.shutdown();
        }
    }

}
