package com.flowable.local.work.service;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.flowable.core.common.api.security.SecurityScope;
import com.flowable.core.idm.api.*;
import com.flowable.core.spring.security.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;


/*
    Returns user information:
    - getCurrentUserGroups()
    - getUserGroups(userId)
 */
@Component
public class UserService {

    protected static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);
    protected final PlatformIdentityService platformIdentityService;

    public UserService(PlatformIdentityService platformIdentityService) {
        this.platformIdentityService = platformIdentityService;
    }

    @NotNull
    public ArrayNode getCurrentUserGroups() {
        LOGGER.debug("Getting current user groups");
        SecurityScope currentUserSecurityScope = SecurityUtils.getCurrentUserSecurityScopeSafe();
        List<String> stringList = new ArrayList<>(currentUserSecurityScope.getGroupKeys());
        return createSortedArrayNode(stringList);
    }

    @NotNull
    protected static ArrayNode createSortedArrayNode(List<String> stringList) {
        Collections.sort(stringList);
        ArrayNode roles = JsonNodeFactory.instance.arrayNode();
        for(String role : stringList) {
            // Apply a role filter here if necessary
            roles.add(role);
        }
        return roles;
    }

    @NotNull
    public ArrayNode getUserGroups(String userId) {
        LOGGER.debug("Getting groups of user {}", userId);
        SecurityScope currentUserSecurityScope = SecurityUtils.getCurrentUserSecurityScopeSafe();
        // Get groups via User Query
        List<String> groupStringList = getLdapEntitlements(userId, currentUserSecurityScope.getTenantId());
        if (groupStringList.isEmpty()) {
            // Get groups via Group Query
            groupStringList = getPlatformGroups(userId, currentUserSecurityScope);
        }
        return createSortedArrayNode(groupStringList);
    }

    @NotNull
    protected List<String> getPlatformGroups(String userId, SecurityScope currentUserSecurityScope) {
        List<PlatformGroup> platformGroups = new ArrayList<>();
        try {
            platformGroups = platformIdentityService.createPlatformGroupQuery()
                    .groupTenantId(currentUserSecurityScope.getTenantId())
                    .groupMember(userId)
                    .list();
        } catch (Exception ignored) {
        }
        List<String> stringList = new ArrayList<>();
        for(PlatformGroup platformGroup : platformGroups) {
            stringList.add(platformGroup.getKey());
        }
        return stringList;
    }

    @NotNull
    protected List<String> getLdapEntitlements(String userId, String tenantId) {
        PlatformUser platformUser = platformIdentityService.createPlatformUserQuery()
                .tenantId(tenantId)
                .userId(userId)
                .includeIdentityInfo()
                .singleResult();
        return Optional.ofNullable(platformUser)
                .map(PlatformUser::getIdentityInfo)
                .flatMap(identityInfos -> identityInfos.stream()
                        .filter(ifInfo -> "ldap_entitlement".equals(ifInfo.getName()))
                        .findFirst())
                .map(PlatformIdentityInfo::getValue)
                .filter(value -> value instanceof String) // Ensure that value is String
                .map(value -> (String) value)
                .map(value -> Arrays.stream(value.split(";"))
                        .filter(val -> !val.trim().isEmpty())
                        .collect(Collectors.toList()))
                .orElseGet(List::of);
    }
}