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

import org.bson.Document;
import org.gcube.application.cms.plugins.faults.EventException;
import org.gcube.application.cms.plugins.faults.InsufficientPrivileges;
import org.gcube.application.cms.plugins.faults.StepException;
import org.gcube.application.cms.tests.Tests;
import org.gcube.application.cms.tests.TokenSetter;
import org.gcube.application.geoportal.common.faults.StorageException;
import org.gcube.application.geoportal.common.model.document.Lock;
import org.gcube.application.geoportal.common.model.document.Project;
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.Field;
import org.gcube.application.geoportal.common.utils.FileSets;
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.gcube.application.geoportal.service.model.internal.faults.*;
import org.gcube.application.geoportal.service.utils.UserUtils;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.File;
import java.io.IOException;

import static junit.framework.TestCase.*;
import static org.junit.Assume.assumeTrue;

public class LockTests extends BasicServiceTestUnit {

    String profileID = "rolesTesting";
    ProfiledMongoManager manager= null;

    @BeforeClass
    public static void setLocalFolder(){
        USE_LOCAL_FOLDER=true;
    }
    @Before
    public void inits() throws RegistrationException, ConfigurationException {
        assumeTrue(GCubeTest.isTestInfrastructureEnabled());
        TokenSetter.set(GCubeTest.getContext());
        manager = new ProfiledMongoManager(profileID);

        // NB Role testing not expected in VRE


        UserUtils.DEFAULT_ROLES.add("FakeAdmin");
    }

    @Test
    public void testLocking() throws StepException, EventException, IOException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess {
        assumeTrue(GCubeTest.isTestInfrastructureEnabled());
        Project p = manager.registerNew(new Document("dummyField","dummyValue"));
        // lock
        p= manager.lock(p.getId(),"Testing");

        assertNotNull(p.getLock());
        assertNotNull(p.getLock().getId());
        assertNotNull(p.getLock().getInfo());
        assertTrue(p.getLock().getOperation().equals("Testing"));

        try{
            Lock l =p.getLock();
            System.out.println("Lock is "+l);
            p = manager.lock(p.getId(),"Should Fail");
            fail("Expected Lock exception. New Lock is  "+p.getLock());
        }catch(ProjectLockedException e){
            // expected lock exception
            System.out.println("Successfully blocked invalid lock operation");
        }

        try{
            Lock l =p.getLock();
            System.out.println("Lock is "+l);
            manager.update(p.getId(),new Document("should","fail"));
            fail("Expected Lock exception. New Lock is  "+p.getLock());
        }catch (ProjectLockedException e){
            // expected lock exception
            System.out.println("Successfully blocked invalid edit operation");
        }

        manager.unlockAndUpdate(p);

        manager.update(p.getId(),new Document("should","fail"));
    }

    @Test
    public void testUnlock() throws StepException, EventException, IOException, ProjectNotFoundException, ProjectLockedException, InvalidLockException, DeletionException, ConfigurationException, StorageHubException, StorageException, InvalidUserRoleException, UnauthorizedAccess, InsufficientPrivileges {
        assumeTrue(GCubeTest.isTestInfrastructureEnabled());
        MongoManagerI<Project> managerInterface = manager;
        // create
        Project p = managerInterface.registerNew(new Document("dummyField","dummyValue"));
        checkIsLockCleaned(p.getId());

        // edit
        p=managerInterface.update(p.getId(),new Document("some","field"));
        checkIsLockCleaned(p.getId());

        // register fileset
        FileSets.RequestBuilder builder = FileSets.build(
                "$.relazioneScavo","fileset","relazioneScavo."+ Field.CHILDREN+"[?(@.fileset)]");
        StorageUtils s= new StorageUtils();
        builder.add(
                s.putOntoStorage(new File(Tests.FOLDER_CONCESSIONI,"pos.shp"),"pos.shp"));

        p= managerInterface.registerFileSet(p.getId(),builder.getTheRequest());
        checkIsLockCleaned(p.getId());

        // delete fileset
        p=managerInterface.deleteFileSet(p.getId(),"$.relazioneScavo.fileset",false);
        checkIsLockCleaned(p.getId());

        // perform step
        p=managerInterface.performStep(p.getId(),"SUBMIT DRAFT",new Document());
        checkIsLockCleaned(p.getId());
    }

    private void checkIsLockCleaned(String id) throws ProjectNotFoundException, InvalidUserRoleException, UnauthorizedAccess {
        assertNull(manager.getByID(id).getLock());
    }
}
