package org.gcube.application.geoportal.service.profiledDocuments;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.bson.Document;
import org.gcube.application.cms.serialization.Serialization;
import org.gcube.application.cms.tests.Tests;
import org.gcube.application.cms.tests.TokenSetter;
import org.gcube.application.cms.tests.model.BasicTests;
import org.gcube.application.geoportal.common.model.configuration.Configuration;
import org.gcube.application.geoportal.common.model.document.Project;
import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation;
import org.gcube.application.geoportal.common.model.rest.QueryRequest;
import org.gcube.application.geoportal.common.model.rest.RegisterFileSetRequest;
import org.gcube.application.geoportal.common.model.rest.StepExecutionRequest;
import org.gcube.application.geoportal.common.rest.InterfaceConstants;
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.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import java.io.File;
import java.util.List;

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

public abstract class AbstractProfiledDocumentsTests extends BasicServiceTestUnit {


	@Before
	public void setContext(){
		assumeTrue(GCubeTest.isTestInfrastructureEnabled());
		TokenSetter.set(GCubeTest.getContext());
	}



	protected WebTarget baseTarget(){
		JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
		provider.setMapper(Serialization.mapper);
		WebTarget toReturn = target(InterfaceConstants.Methods.PROJECTS).register(provider);
		return toReturn;
	};



	@Test
	public void getAll() {
		assumeTrue(GCubeTest.isTestInfrastructureEnabled());
		System.out.println(baseTarget().request(MediaType.APPLICATION_JSON).get(List.class));
	}

	@Test
	public void getByID(){
		assumeTrue(GCubeTest.isTestInfrastructureEnabled());
		baseTarget().request(MediaType.APPLICATION_JSON).get(List.class).forEach(d ->{

			try {
				check(baseTarget().path((Serialization.convert(d, Project.class)).getId())
						.request(MediaType.APPLICATION_JSON).get(), Project.class);
			} catch (Exception e) {
				e.printStackTrace(System.err);
				Assert.fail(e.getMessage());
			}
		});
	}

	@Test
	public void getConfiguration() throws Exception {
		assumeTrue(GCubeTest.isTestInfrastructureEnabled());
		System.out.println(check(
				baseTarget().path(InterfaceConstants.Methods.CONFIGURATION_PATH).request(MediaType.APPLICATION_JSON).get(),Configuration.class));
	}

	// Queries
	@Test
	public void query() throws JsonProcessingException {
		assumeTrue(GCubeTest.isTestInfrastructureEnabled());
		System.out.println(baseTarget().path(InterfaceConstants.Methods.QUERY_PATH).
				request(MediaType.APPLICATION_JSON).
				post(Entity.entity(Serialization.write(new QueryRequest()),MediaType.APPLICATION_JSON)));
	}

	// CREATE / edit / delete



	// @@@@@@@@@@@@@@@  Routines

	protected Project createNew(Document content) throws Exception {


		Project doc =check(baseTarget().request(MediaType.APPLICATION_JSON).
				post(Entity.entity(content, MediaType.APPLICATION_JSON)), Project.class);
		BasicTests.validate(doc);
		assertTrue(doc.getLifecycleInformation().getPhase().equals(LifecycleInformation.CommonPhases.DRAFT_PHASE));
		return doc;
	}

	protected void delete(String id) throws Exception {
		delete(id,false);
	}

	protected void delete(String id,Boolean force) throws Exception {
		check(baseTarget().path(id).queryParam("force",force).request(MediaType.APPLICATION_JSON).
				delete(), null);
	}

	
	protected Project update(String id, Document newContent)throws Exception {
		Project doc = check(baseTarget().path(id).request(MediaType.APPLICATION_JSON).
				put(Entity.entity(newContent, MediaType.APPLICATION_JSON)), Project.class);
		BasicTests.validate(doc);
		return doc;
	}

	protected Project upload(StorageUtils storage,
                             String id,
                             String parentPath,
                             String fieldName,
                             String fieldDefinitionPath,
                             Document attributes,
                             RegisterFileSetRequest.ClashOptions clashPolicy,
                             String ...files) throws Exception {
		FileSets.RequestBuilder builder = FileSets.build(parentPath,fieldName,fieldDefinitionPath);

		builder.setClashPolicy(clashPolicy).setAttributes(attributes);

		for(String file:files)
			builder.add(storage.putOntoStorage(new File(Tests.BASE_FOLDER,file),file));

		Project doc = check(baseTarget().path(InterfaceConstants.Methods.REGISTER_FILES_PATH).path(id).request(MediaType.APPLICATION_JSON).
				post(Entity.entity(Serialization.write(builder.getTheRequest()),
						MediaType.APPLICATION_JSON)), Project.class);
		BasicTests.validate(doc);
		return doc;
	}


	protected Project step(String id, StepExecutionRequest request) throws Exception {
		Project toReturn= check(baseTarget().
				path(InterfaceConstants.Methods.STEP).path(id).request(MediaType.APPLICATION_JSON).
				post(Entity.entity(Serialization.write(request),
						MediaType.APPLICATION_JSON)), Project.class);
		BasicTests.validate(toReturn);
		assertTrue(toReturn.getLifecycleInformation().getLastInvokedStep().equals(request.getStepID()));
		return toReturn;
	}

}
