package cz.muni.ics.oidc.server.claims.sources;

import com.fasterxml.jackson.databind.JsonNode;
import cz.muni.ics.oidc.PerunConstants;
import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.Group;
import cz.muni.ics.oidc.server.claims.ClaimSource;
import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext;
import cz.muni.ics.oidc.server.claims.ClaimSourceProduceContext;
import cz.muni.ics.oidc.server.claims.ClaimUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Source fetches all unique group names in context of user and facility. If no facility exists for the client, empty
 * list is returned as result.
 *
 * @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
 */
@Slf4j
public class GroupNamesSource extends ClaimSource {

	public GroupNamesSource(ClaimSourceInitContext ctx) {
		super(ctx);
		log.debug("{} - initialized", getClaimName());
	}

	@Override
	public Set<String> getAttrIdentifiers() {
		return Collections.emptySet();
	}

	@Override
	public JsonNode produceValue(ClaimSourceProduceContext pctx) {
		Map<Long, String> idToNameMap = this.produceGroupNames(pctx);
		JsonNode result = ClaimUtils.convertResultStringsToJsonArray(new HashSet<>(idToNameMap.values()));
		log.debug("{} - produced value for user({}): '{}'", getClaimName(), pctx.getPerunUserId(), result);
		return result;
	}

	protected Map<Long, String> produceGroupNames(ClaimSourceProduceContext pctx) {
		log.trace("{} - produce group names with trimming 'members' part of the group names", getClaimName());
		Facility facility = pctx.getFacility();
		Set<Group> userGroups = ClaimUtils.getUserGroupsOnFacility(facility, pctx.getPerunUserId(),
				pctx.getPerunAdapter(), getClaimName(), null);
		return getGroupIdToNameMap(userGroups, true);
	}

	protected Map<Long, String> getGroupIdToNameMap(Set<Group> userGroups, boolean trimMembers) {
		Map<Long, String> idToNameMap = new HashMap<>();
		userGroups.forEach(g -> {
			String uniqueName = g.getUniqueGroupName();
			if (trimMembers && StringUtils.hasText(uniqueName) && PerunConstants.GROUP_NAME_MEMBERS.equals(g.getName())) {
				uniqueName = uniqueName.replace(':' + PerunConstants.GROUP_NAME_MEMBERS, "");
				g.setUniqueGroupName(uniqueName);
			}

			idToNameMap.put(g.getId(), g.getUniqueGroupName());
		});

		log.trace("{} - group ID to group name map: '{}'", getClaimName(), idToNameMap);
		return idToNameMap;
	}

}
