package eu.dnetlib.openaire.community;

import static eu.dnetlib.openaire.common.ExporterConstants.C;
import static eu.dnetlib.openaire.common.ExporterConstants.C_CP;
import static eu.dnetlib.openaire.common.ExporterConstants.C_O;
import static eu.dnetlib.openaire.common.ExporterConstants.C_PJ;
import static eu.dnetlib.openaire.common.ExporterConstants.C_ZC;
import static eu.dnetlib.openaire.common.ExporterConstants.R;
import static eu.dnetlib.openaire.common.ExporterConstants.W;

import java.util.List;

import eu.dnetlib.openaire.exporter.exceptions.CommunityException;
import eu.dnetlib.openaire.exporter.exceptions.CommunityNotFoundException;
import eu.dnetlib.openaire.exporter.model.community.CommunityContentprovider;
import eu.dnetlib.openaire.exporter.model.community.CommunityDetails;
import eu.dnetlib.openaire.exporter.model.community.CommunityOpenAIRECommunities;
import eu.dnetlib.openaire.exporter.model.community.CommunityOrganization;
import eu.dnetlib.openaire.exporter.model.community.CommunityProject;
import eu.dnetlib.openaire.exporter.model.community.CommunitySummary;
import eu.dnetlib.openaire.exporter.model.community.CommunityWritableProperties;
import eu.dnetlib.openaire.exporter.model.community.CommunityZenodoCommunity;
import eu.dnetlib.openaire.exporter.model.community.selectioncriteria.SelectionCriteria;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;

@RestController
@CrossOrigin(origins = {
	"*"
})
@ConditionalOnProperty(value = "openaire.exporter.enable.community", havingValue = "true")
@Tag(name = "OpenAIRE Communities API", description = "the OpenAIRE Community API")
public class CommunityApiController {

	@Autowired
	private CommunityApiCore communityApiCore;

	@RequestMapping(value = "/community/communities", produces = {
		"application/json"
	}, method = RequestMethod.GET)
	@Operation(summary = "get all community profiles", description = "get all community profiles", tags = {
		C, R
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public List<CommunitySummary> listCommunities() throws CommunityException {
		return communityApiCore.listCommunities();
	}

	@RequestMapping(value = "/community/{id}", produces = {
		"application/json"
	}, method = RequestMethod.GET)
	@Operation(summary = "get community profile", description = "get community profile", tags = {
		C, R
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public CommunityDetails getCommunity(@PathVariable final String id) throws CommunityException, CommunityNotFoundException {
		return communityApiCore.getCommunity(id);
	}

	@RequestMapping(value = "/community/{id}", produces = {
		"application/json"
	}, method = RequestMethod.POST)
	@Operation(summary = "update community details", description = "update community details", tags = {
		C, R
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public void setCommunity(
		@PathVariable final String id,
		@RequestBody final CommunityWritableProperties properties) throws CommunityException, CommunityNotFoundException {

		communityApiCore.setCommunity(id, properties);
	}

	@RequestMapping(value = "/community/{id}/projects", produces = {
		"application/json"
	}, method = RequestMethod.GET)
	@Operation(summary = "get community projects", description = "get community projects", tags = {
		C_PJ, R
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public List<CommunityProject> getCommunityProjects(@PathVariable final String id) throws CommunityException, CommunityNotFoundException {
		return communityApiCore.getCommunityProjects(id);
	}

	@RequestMapping(value = "/community/{id}/projects", produces = {
		"application/json"
	}, method = RequestMethod.POST)
	@Operation(summary = "associate a project to the community", description = "associate a project to the community", tags = {
		C_PJ, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public CommunityProject addCommunityProject(
		@PathVariable final String id,
		@RequestBody final CommunityProject project) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunityProject(id, project);
	}

	@RequestMapping(value = "/community/{id}/projects", produces = {
		"application/json"
	}, method = RequestMethod.DELETE)
	@Operation(summary = "remove a project from the community", description = "remove a project from the community", tags = {
		C_PJ, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public void deleteCommunityProject(
		@PathVariable final String id,
		@RequestBody final Integer projectId) throws CommunityException, CommunityNotFoundException {

		communityApiCore.removeCommunityProject(id, projectId);
	}

	@RequestMapping(value = "/community/{id}/projectList", produces = {
			"application/json"
	}, method = RequestMethod.POST)
	@Operation(summary = "associate a list of project to the community",
			description = "associate a list of project to the community", tags = {
			C_PJ, W
	})
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public List<CommunityProject> addCommunityProjectList(
			@PathVariable final String id,
			@RequestBody final List<CommunityProject> projectList) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunityProjectList(id, projectList);
	}

	@RequestMapping(value = "/community/{id}/projectList", produces = {
			"application/json"
	}, method = RequestMethod.DELETE)
	@Operation(summary = "remove a list of projects from the community",
			description = "remove a list of projects from the community", tags = {
			C_PJ, W
	})
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public void deleteCommunityProjectList(
			@PathVariable final String id,
			@RequestBody final List<Integer> projectIdList) throws CommunityException, CommunityNotFoundException {

		communityApiCore.removeCommunityProjectList(id, projectIdList);
	}

	@RequestMapping(value = "/community/{id}/contentproviders", produces = {
		"application/json"
	}, method = RequestMethod.GET)
	@Operation(summary = "get the list of content providers associated to a given community", description = "get the list of content providers associated to a given community", tags = {
		C_CP, R
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public List<CommunityContentprovider> getCommunityContentproviders(@PathVariable final String id) throws CommunityException, CommunityNotFoundException {
		return communityApiCore.getCommunityContentproviders(id);
	}

	@RequestMapping(value = "/community/{id}/contentproviders", produces = {
		"application/json"
	}, method = RequestMethod.POST)
	@Operation(summary = "associate a content provider to the community", description = "associate a content provider to the community", tags = {
		C_CP, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public CommunityContentprovider addCommunityContentprovider(
		@PathVariable final String id,
		@RequestBody final CommunityContentprovider contentprovider) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunityContentprovider(id, contentprovider);
	}

	@RequestMapping(value = "/community/{id}/contentproviders", produces = {
		"application/json"
	}, method = RequestMethod.DELETE)
	@Operation(summary = "remove the association between a content provider and the community", description = "remove the association between a content provider and the community", tags = {
		C_CP, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public void removeCommunityContentprovider(
		@PathVariable final String id,
		@RequestBody final Integer contentproviderId) throws CommunityException, CommunityNotFoundException {

		communityApiCore.removeCommunityContentProvider(id, contentproviderId);
	}

	@RequestMapping(value = "/community/{id}/contentprovidersList", produces = {
			"application/json"
	}, method = RequestMethod.POST)
	@Operation(summary = "associate a list of content providers to the community",
			description = "associate a list of content providers to the community", tags = {
			C_PJ, W
	})
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public List<CommunityContentprovider> addCommunityContentProvidersList(
			@PathVariable final String id,
			@RequestBody final List<CommunityContentprovider> contentprovidersList) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunityContentProvidersList(id, contentprovidersList);
	}

	@RequestMapping(value = "/community/{id}/contentprovidersList", produces = {
			"application/json"
	}, method = RequestMethod.DELETE)
	@Operation(summary = "remove a list of content providers from the community",
			description = "remove a list of content providers from the community", tags = {
			C_PJ, W
	})
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public void deleteCommunityContentProvidersList(
			@PathVariable final String id,
			@RequestBody final List<Integer> contentProviderIdList) throws CommunityException, CommunityNotFoundException {

		communityApiCore.removeCommunityContentProviderList(id, contentProviderIdList);
	}

	// ADDING CODE FOR COMMUNITY ORGANIZATIONS

	@RequestMapping(value = "/community/{id}/organizations", produces = {
		"application/json"
	}, method = RequestMethod.GET)
	@Operation(summary = "get the list of organizations for a given community", description = "get the list of organizations for a given community", tags = {
		C_O, R
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public List<CommunityOrganization> getCommunityOrganizations(@PathVariable final String id) throws CommunityException, CommunityNotFoundException {
		return communityApiCore.getCommunityOrganizations(id);
	}

	@RequestMapping(value = "/community/{id}/organizations", produces = {
		"application/json"
	}, method = RequestMethod.POST)
	@Operation(summary = "associate an organization to the community", description = "associate an organization to the community", tags = {
		C_O, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public CommunityOrganization addCommunityOrganization(
		@PathVariable final String id,
		@RequestBody final CommunityOrganization organization) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunityOrganization(id, organization);
	}

	@RequestMapping(value = "/community/{id}/organizations", produces = {
		"application/json"
	}, method = RequestMethod.DELETE)
	@Operation(summary = "remove the association between an organization and the community", description = "remove the association between an organization and the community", tags = {
		C_O, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public void removeCommunityOrganization(
		@PathVariable final String id,
		@RequestBody final Integer organizationId) throws CommunityException, CommunityNotFoundException {

		communityApiCore.removeCommunityOrganization(id, organizationId);
	}
	// **********************

	@RequestMapping(value = "/community/{id}/subjects", produces = {
		"application/json"
	}, method = RequestMethod.POST)
	@Operation(summary = "associate a subject to the community", description = "associate a subject to the community", tags = {
		C, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public CommunityDetails addCommunitySubjects(
		@PathVariable final String id,
		@RequestBody final List<String> subjects) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunitySubjects(id, subjects);
	}

	@RequestMapping(value = "/community/{id}/subjects", produces = {
		"application/json"
	}, method = RequestMethod.DELETE)
	@Operation(summary = "remove subjects from a community", description = "remove subjects from a community", tags = {
		C, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public CommunityDetails removeCommunitySubjects(
		@PathVariable final String id,
		@RequestBody final List<String> subjects) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.removeCommunitySubjects(id, subjects);
	}
	@RequestMapping(value = "/community/{id}/fos", produces = { "application/json" }, method = RequestMethod.POST)
	@Operation(
			summary = "associate a fos to the community",
			description = "associate a fos to the community",
			tags = { C, W })
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error") })
	public CommunityDetails addCommunityFOS(
			@PathVariable final String id,
			@RequestBody final List<String> subjects) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunityFOS(id, subjects);
	}

	@RequestMapping(value = "/community/{id}/fos", produces = { "application/json" }, method = RequestMethod.DELETE)
	@Operation(
			summary = "remove fos from a community",
			description = "remove fos from a community",
			tags = { C, W })
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error") })
	public CommunityDetails removeCommunityFOS(
			@PathVariable final String id,
			@RequestBody final List<String> subjects) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.removeCommunityFOS(id, subjects);
	}


	@RequestMapping(value = "/community/{id}/sdg", produces = { "application/json" }, method = RequestMethod.POST)
	@Operation(
			summary = "associate a sdg to the community",
			description = "associate a sdg to the community",
			tags = { C, W })
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error") })
	public CommunityDetails addCommunitySDG(
			@PathVariable final String id,
			@RequestBody final List<String> subjects) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunitySDG(id, subjects);
	}

	@RequestMapping(value = "/community/{id}/sdg", produces = { "application/json" }, method = RequestMethod.DELETE)
	@Operation(
			summary = "remove sdg from a community",
			description = "remove sdg from a community",
			tags = { C, W })
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error") })
	public CommunityDetails removeCommunitySDG(
			@PathVariable final String id,
			@RequestBody final List<String> subjects) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.removeCommunitySDG(id, subjects);
	}

	@RequestMapping(value = "/community/{id}/advancedConstraint", produces = { "application/json" }, method = RequestMethod.POST)
	@Operation(
			summary = "the set of constraints to be used to extend the association between result and community",
			description = "the set of constraints to be used to extend the association between result and community",
			tags = { C, W })
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error") })
	public CommunityDetails addAdvancedConstraint(
			@PathVariable final String id,
			@RequestBody final SelectionCriteria advancedConstraint) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunityAdvancedConstraint(id, advancedConstraint);
	}

	@RequestMapping(value = "/community/{id}/advancedConstraint", produces = { "application/json" }, method = RequestMethod.DELETE)
	@Operation(
			summary = "remove the constraints to extend the association result community from a community",
			description = "remove the constraints to extend the association result community from a community",
			tags = { C, W })
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "OK"),
			@ApiResponse(responseCode = "404", description = "not found"),
			@ApiResponse(responseCode = "500", description = "unexpected error") })
	public CommunityDetails removeAdvancedConstraint(
			@PathVariable final String id) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.removeCommunityAdvancedConstraint(id);
	}

	@RequestMapping(value = "/community/{id}/zenodocommunities", produces = {
		"application/json"
	}, method = RequestMethod.GET)
	@Operation(summary = "get the list of Zenodo communities associated to a given community", description = "get the list of Zenodo communities associated to a given community", tags = {
		C_ZC, R
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public List<CommunityZenodoCommunity> getCommunityZenodoCommunities(@PathVariable final String id) throws CommunityException, CommunityNotFoundException {
		return communityApiCore.getCommunityZenodoCommunities(id);
	}

	@RequestMapping(value = "/community/{id}/zenodocommunities", produces = {
		"application/json"
	}, method = RequestMethod.POST)
	@Operation(summary = "associate a Zenodo community to the community", description = "associate a Zenodo community to the community", tags = {
		C_ZC, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public CommunityZenodoCommunity addCommunityZenodoCommunity(
		@PathVariable final String id,
		@RequestBody final CommunityZenodoCommunity zenodocommunity) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.addCommunityZenodoCommunity(id, zenodocommunity);

	}

	@RequestMapping(value = "/community/{id}/zenodocommunities", produces = {
		"application/json"
	}, method = RequestMethod.DELETE)
	@Operation(summary = "remove a Zenodo community from a community", description = "remove a Zenodo community from a community", tags = {
		C_ZC, W
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public void removeCommunityZenodoCommunity(
		@PathVariable final String id,
		@RequestBody final Integer zenodoCommId) throws CommunityException, CommunityNotFoundException {

		communityApiCore.removeCommunityZenodoCommunity(id, zenodoCommId);

	}

	@RequestMapping(value = "/community/{zenodoId}/openairecommunities", produces = {
		"application/json"
	}, method = RequestMethod.GET)
	@Operation(summary = "get the list of OpenAIRE communities associated to a given Zenodo community", description = "get the list of OpenAIRE communities associated to a given Zenodo community", tags = {
		C_ZC, R
	})
	@ApiResponses(value = {
		@ApiResponse(responseCode = "200", description = "OK"),
		@ApiResponse(responseCode = "404", description = "not found"),
		@ApiResponse(responseCode = "500", description = "unexpected error")
	})
	public CommunityOpenAIRECommunities getOpenAireCommunities(
		@PathVariable final String zenodoId) throws CommunityException, CommunityNotFoundException {

		return communityApiCore.getOpenAIRECommunities(zenodoId);

	}
}
