package org.kuali.coeus.sys.impl.auth;

import com.codiform.moo.curry.Translate;
import org.apache.commons.lang3.StringUtils;
import org.kuali.coeus.sys.framework.auth.RoleMembershipDto;
import org.kuali.coeus.sys.framework.controller.rest.RestController;
import org.kuali.coeus.sys.framework.rest.ResourceNotFoundException;
import org.kuali.rice.core.api.membership.MemberType;
import org.kuali.rice.kim.api.KimConstants;
import org.kuali.rice.kim.api.role.RoleMembership;
import org.kuali.rice.kim.api.role.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

import static org.kuali.coeus.sys.framework.util.CollectionUtils.entry;
import static org.kuali.coeus.sys.framework.util.CollectionUtils.entriesToMap;

@Controller("RoleMembershipController")
public class RoleMembershipController extends RestController {

	private static final String NAMESPACE_NAME_DELIMETER = ":";
	private static final String QUALIFIER_NAME_VALUE_DELIMETER = ":";

	@Autowired
	@Qualifier("roleService")
	private RoleService roleService;

	@RequestMapping(method= RequestMethod.GET, value="v1/roles/{roleId}/principals/{memberId}")
	public @ResponseBody List<RoleMembershipDto> getRoleMembership(@PathVariable String roleId, @PathVariable String memberId, @RequestParam(value="qualification", required=false) String[] qualification) {
		if (StringUtils.isBlank(roleId)) {
			throw new ResourceNotFoundException("roleId is blank");
		}

		if (StringUtils.isBlank(memberId)) {
			throw new ResourceNotFoundException("memberId is blank");
		}

		final Map<String, String> qualificationMap = withPrincipalQualifier(memberId, getQualifierMap(qualification != null ? Arrays.asList(qualification) : Collections.emptyList()));

		final List<RoleMembership> roleMembers = roleService.getRoleMembers(Collections.singletonList(getActualRoleId(roleId)), qualificationMap).stream()
				.filter(m -> m.getType() == MemberType.PRINCIPAL)
				.filter(m -> m.getMemberId().equals(memberId))
				.collect(Collectors.toList());

		if (roleMembers.isEmpty()) {
			throw new ResourceNotFoundException("no results");
		}

		return Translate.to(RoleMembershipDto.class).fromEach(roleMembers);

	}

	/**
	 * Some roles like the user role require a principal qualifier to make a match.
	 */
	protected Map<String, String> withPrincipalQualifier(String memberId, Map<String, String> qualificationMap) {
		final HashMap<String, String> map = new HashMap<>(qualificationMap);
		map.put(KimConstants.AttributeConstants.PRINCIPAL_ID, memberId);
		return map;
	}

	protected Map<String, String> getQualifierMap(List<String> qualification) {
		return qualification.stream().map(qualifier -> {
			final String[] q = qualifier.split(QUALIFIER_NAME_VALUE_DELIMETER);
			return entry(q[0], q[1]);
		}).collect(entriesToMap());
	}

	protected String getActualRoleId(String roleId) {
		final String actualRoleId;
		if (roleId.contains(NAMESPACE_NAME_DELIMETER)) {
			final String[] namespaceAndName = roleId.split(NAMESPACE_NAME_DELIMETER);
			final String namespace = namespaceAndName[0];
			final String name = namespaceAndName[1];
			if (StringUtils.isBlank(namespace)) {
				throw new ResourceNotFoundException("blank namespace from roleId");
			}

			if (StringUtils.isBlank(name)) {
				throw new ResourceNotFoundException("blank name from roleId");
			}

			actualRoleId = roleService.getRoleIdByNamespaceCodeAndName(namespace, name);
		} else {
			actualRoleId = roleId;
		}

		if (StringUtils.isBlank(actualRoleId)) {
			throw new ResourceNotFoundException("roleId not found");
		}
		return actualRoleId;
	}

	public RoleService getRoleService() {
		return roleService;
	}

	public void setRoleService(RoleService roleService) {
		this.roleService = roleService;
	}
}

@@ -1414,16 +1414,28 @@
 mbership
+sForMemberId
 (@PathVa
@@ -2406,16 +2406,1014 @@
 );%0A%0A%09%7D%0A%0A
+    @RequestMapping(method= RequestMethod.GET, value=%22v1/roles/%7BroleId%7D/principals%22)%0A    public @ResponseBody List%3CRoleMembershipDto%3E getRoleMemberships(@PathVariable String roleId, @RequestParam(value=%22qualification%22, required=false) String%5B%5D qualification) %7B%0A        if (StringUtils.isBlank(roleId)) %7B%0A            throw new ResourceNotFoundException(%22roleId is blank%22);%0A        %7D%0A%0A        final Map%3CString, String%3E qualificationMap = getQualifierMap(qualification != null ? Arrays.asList(qualification) : Collections.emptyList());%0A%0A        final List%3CRoleMembership%3E roleMembers = roleService.getRoleMembers(Collections.singletonList(getActualRoleId(roleId)), qualificationMap).stream()%0A                .filter(m -%3E m.getType() == MemberType.PRINCIPAL)%0A                .collect(Collectors.toList());%0A%0A        if (roleMembers.isEmpty()) %7B%0A            throw new ResourceNotFoundException(%22no results%22);%0A        %7D%0A%0A        return Translate.to(RoleMembershipDto.class).fromEach(roleMembers);%0A%0A    %7D%0A%0A
 %09/**%0A%09 *

add membership end point to get all principals with a specified role