/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with this
 * work for additional information regarding copyright ownership. The ASF
 * licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.apache.sling.feature.cpconverter.accesscontrol;

import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.PrivilegeDefinition;
import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
import org.apache.jackrabbit.vault.fs.spi.PrivilegeDefinitions;
import org.apache.jackrabbit.vault.util.PlatformNameFormat;
import org.apache.sling.feature.cpconverter.features.FeaturesManager;
import org.apache.sling.feature.cpconverter.shared.RepoPath;
import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.jcr.NamespaceException;
import java.io.File;
import java.io.FileInputStream;
import java.util.Optional;
import java.util.Formatter;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.Objects;
import java.util.Map.Entry;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class DefaultAclManager implements AclManager {

    private static final String CONTENT_XML_FILE_NAME = ".content.xml";

    private final boolean enforcePrincipalBased;
    private final RepoPath supportedPrincipalBasedPath;

    private final Set<SystemUser> systemUsers = new LinkedHashSet<>();
    private final Set<Group> groups = new LinkedHashSet<>();
    private final Set<User> users = new LinkedHashSet<>();

    private final Map<String, List<AccessControlEntry>> acls = new HashMap<>();

    private final List<String> nodetypeRegistrationSentences = new LinkedList<>();

    private volatile PrivilegeDefinitions privilegeDefinitions;

    public DefaultAclManager() {
        this(false, null);
    }
    public DefaultAclManager(boolean enforcePrincipalBased, @Nullable String supportedPrincipalBasedPath) {
        this.enforcePrincipalBased = enforcePrincipalBased;
        this.supportedPrincipalBasedPath = (supportedPrincipalBasedPath == null) ? null : new RepoPath(supportedPrincipalBasedPath);
    }

    @Override
    public boolean addUser(@NotNull User user) {
        return users.add(user);
    }

    @Override
    public boolean addGroup(@NotNull Group group) {
        return groups.add(group);
    }

    @Override
    public boolean addSystemUser(@NotNull SystemUser systemUser) {
        return systemUsers.add(systemUser);
    }

    @Override
    public boolean addAcl(@NotNull String systemUser, @NotNull AccessControlEntry acl) {
        if (getSystemUser(systemUser).isPresent()) {
            acls.computeIfAbsent(systemUser, k -> new LinkedList<>()).add(acl);
            return true;
        }
        return false;
    }

    @Override
    public void addRepoinitExtension(@NotNull List<VaultPackageAssembler> packageAssemblers, @NotNull FeaturesManager featureManager) {
        try (Formatter formatter = new Formatter()) {

            if (privilegeDefinitions != null) {
                registerPrivileges(privilegeDefinitions, formatter);
            }

            for (String nodetypeRegistrationSentence : nodetypeRegistrationSentences) {
                formatter.format("%s%n", nodetypeRegistrationSentence);
            }

            addUsersAndGroups(formatter);
            addPaths(formatter, packageAssemblers);

            // add the acls
            acls.forEach((systemUserID, authorizations) ->
                    getSystemUser(systemUserID).ifPresent(systemUser ->
                            addStatements(systemUser, authorizations, formatter)
                    ));

            String text = formatter.toString();

            if (!text.isEmpty()) {
                featureManager.addOrAppendRepoInitExtension(text, null);
            }
        }
    }

    private void addUsersAndGroups(@NotNull Formatter formatter) {
        for (SystemUser systemUser : systemUsers) {
            // make sure all system users are created first
            formatter.format("create service user %s with path %s%n", systemUser.getId(), calculateIntermediatePath(systemUser.getIntermediatePath()));
            if (aclIsBelow(systemUser.getPath())) {
                throw new IllegalStateException("Detected policy on subpath of system-user: " + systemUser);
            }
        }

        for (Group group : groups) {
            if (aclStartsWith(group.getPath())) {
                formatter.format("create group %s with path %s%n", group.getId(), group.getIntermediatePath());
            }
            if (aclIsBelow(group.getPath())) {
                throw new IllegalStateException("Detected policy on subpath of group: " + group);
            }
        }

        for (User user : users) {
            if (aclStartsWith(user.getPath())) {
                throw new IllegalStateException("Detected policy on user: " + user);
            }
        }
    }

    @NotNull
    private String calculateIntermediatePath(@NotNull RepoPath intermediatePath) {
        if (enforcePrincipalBased && supportedPrincipalBasedPath != null && !intermediatePath.startsWith(supportedPrincipalBasedPath)) {
            RepoPath parent = intermediatePath.getParent();
            while (parent != null) {
                if (supportedPrincipalBasedPath.startsWith(parent)) {
                    String relpath = intermediatePath.toString().substring(parent.toString().length());
                    return supportedPrincipalBasedPath.toString() + relpath;
                }
                parent = parent.getParent();
            }
            throw new IllegalStateException("Cannot calculate intermediate path for service user. Configured Supported path " +supportedPrincipalBasedPath+" has no common ancestor with "+intermediatePath);
        } else {
            return intermediatePath.toString();
        }
    }

    private void addPaths(@NotNull Formatter formatter, @NotNull List<VaultPackageAssembler> packageAssemblers) {
        if (!enforcePrincipalBased) {
            Set<RepoPath> paths = acls.entrySet().stream()
                    .filter(entry -> getSystemUser(entry.getKey()).isPresent())
                    .map(Entry::getValue)
                    .flatMap(Collection::stream)
                    // paths only should/need to be create with resource-based access control
                    .filter(((Predicate<AccessControlEntry>) AccessControlEntry::isPrincipalBased).negate())
                    .map(AccessControlEntry::getRepositoryPath)
                    .collect(Collectors.toSet());

            paths.stream()
                    .filter(path -> paths.stream().noneMatch(other -> !other.equals(path) && other.startsWith(path)))
                    .filter(((Predicate<RepoPath>)RepoPath::isRepositoryPath).negate())
                    .filter(path -> Stream.of(systemUsers, users, groups).flatMap(Collection::stream)
                            .noneMatch(user -> user.getPath().startsWith(path)))
                    .map(path -> computePathWithTypes(path, packageAssemblers))
                    .filter(Objects::nonNull)
                    .forEach(
                            path -> formatter.format("create path %s%n", path)
                    );
        }
    }

    private boolean aclStartsWith(@NotNull RepoPath path) {
        return acls.values().stream().flatMap(List::stream).anyMatch(acl -> acl.getRepositoryPath().startsWith(path));
    }

    private boolean aclIsBelow(@NotNull RepoPath path) {
        return acls.values().stream().flatMap(List::stream).anyMatch(acl -> acl.getRepositoryPath().startsWith(path) && !acl.getRepositoryPath().equals(path));
    }

    private void addStatements(@NotNull SystemUser systemUser,
                               @NotNull List<AccessControlEntry> authorizations,
                               @NotNull Formatter formatter) {
        Map<AccessControlEntry, String> resourceEntries = new LinkedHashMap<>();
        Map<AccessControlEntry, String> principalEntries = new LinkedHashMap<>();

        authorizations.forEach(entry -> {
            String path = getRepoInitPath(entry.getRepositoryPath(), systemUser);
            if (enforcePrincipalBased || entry.isPrincipalBased()) {
                principalEntries.put(entry, path);
            } else {
                resourceEntries.put(entry, path);
            }
        });

        if (!principalEntries.isEmpty()) {
            formatter.format("set principal ACL for %s%n", systemUser.getId());
            principalEntries.forEach((entry, path) -> writeEntry(entry, path, formatter));
            formatter.format("end%n");
        }
        if (!resourceEntries.isEmpty()) {
            formatter.format("set ACL for %s%n", systemUser.getId());
            resourceEntries.forEach((entry, path) -> writeEntry(entry, path, formatter));
            formatter.format("end%n");
        }
    }

    private void writeEntry(@NotNull AccessControlEntry entry, @NotNull String path, @NotNull Formatter formatter) {
        formatter.format("%s %s on %s",
                entry.getOperation(),
                entry.getPrivileges(),
                path);

        if (!entry.getRestrictions().isEmpty()) {
            formatter.format(" restriction(%s)",
                    String.join(",", entry.getRestrictions()));
        }

        formatter.format("%n");
    }

    private @NotNull Optional<SystemUser> getSystemUser(@NotNull String id) {
        return systemUsers.stream().filter(systemUser ->  systemUser.getId().equals(id)).findFirst();
    }

    @Override
    public void addNodetypeRegistrationSentence(@NotNull String nodetypeRegistrationSentence) {
        nodetypeRegistrationSentences.add(nodetypeRegistrationSentence);
    }

    @Override
    public void addPrivilegeDefinitions(@NotNull PrivilegeDefinitions privilegeDefinitions) {
        this.privilegeDefinitions = privilegeDefinitions;
    }

    @Override
    public void reset() {
        systemUsers.clear();
        acls.clear();
        nodetypeRegistrationSentences.clear();
        privilegeDefinitions = null;
    }

     protected @Nullable String computePathWithTypes(@NotNull RepoPath path, @NotNull List<VaultPackageAssembler> packageAssemblers) {
        path = new RepoPath(PlatformNameFormat.getPlatformPath(path.toString()));

        boolean type = false;
        String current = "";
        for (String part : path.toString().substring(1).split("/")) {
            current += current.isEmpty() ? part : "/" + part;
            for (VaultPackageAssembler packageAssembler : packageAssemblers) {
                File currentContent = packageAssembler.getEntry(current + "/" + CONTENT_XML_FILE_NAME);
                if (currentContent.isFile()) {
                    String primary;
                    String mixin;
                    try (FileInputStream input = new FileInputStream(currentContent);
                         FileInputStream input2 = new FileInputStream(currentContent)) {
                        primary = new PrimaryTypeParser().parse(input);
                        mixin = new MixinParser().parse(input2);
                        current += "(" + primary;
                        if (mixin != null) {
                            mixin = mixin.trim();
                            if (mixin.startsWith("[")) {
                                mixin = mixin.substring(1, mixin.length() - 1);
                            }
                            current += " mixin " + mixin;
                        }
                        current += ")";
                        type = true;
                    } catch (Exception e) {
                        throw new RuntimeException("A fatal error occurred while parsing the '"
                                + currentContent
                                + "' file, see nested exceptions: "
                                + e);
                    }
                }
            }
        }

        return type ? new RepoPath(current).toString() : null;
    }

    @NotNull
    private String getRepoInitPath(@NotNull RepoPath path, @NotNull SystemUser systemUser) {
        if (path.isRepositoryPath()) {
            return ":repository";
        } else if (isHomePath(path, systemUser.getPath())) {
            return getHomePath(systemUser);
        } else {
            AbstractUser other = getOtherUser(path, Stream.of(systemUsers, groups).flatMap(Collection::stream));
            if (other != null) {
                return getHomePath(other);
            }
            // not a special path
            return path.toString();
        }
    }

    private boolean isHomePath(@NotNull RepoPath path, @NotNull RepoPath systemUserPath) {
        // ACE located in the subtree are not supported
        return path.equals(systemUserPath);
    }

    @Nullable
    private static AbstractUser getOtherUser(@NotNull RepoPath path, @NotNull Stream<? extends AbstractUser> abstractUsers) {
        return abstractUsers.filter(au -> path.startsWith(au.getPath())).findFirst().orElse(null);
    }

    @NotNull
    private String getHomePath(@NotNull AbstractUser abstractUser) {
        // since ACEs located in the subtree of a user are not supported by the converter,
        // there is no need to calculate a potential sub-path to be appended.
        return "home("+abstractUser.getId()+")";
    }

    private static void registerPrivileges(@NotNull PrivilegeDefinitions definitions, @NotNull Formatter formatter) {
        NameResolver nameResolver = new DefaultNamePathResolver(definitions.getNamespaceMapping());
        for (PrivilegeDefinition privilege : definitions.getDefinitions()) {
            try {
                String name = nameResolver.getJCRName(privilege.getName());
                String aggregates = getAggregatedNames(privilege, nameResolver);
                if (privilege.isAbstract()) {
                    formatter.format("register abstract privilege %s%s%n", name, aggregates);
                } else {
                    formatter.format("register privilege %s%s%n", name, aggregates);
                }
            } catch (NamespaceException e) {
                throw new IllegalStateException(e);
            }
        }
    }

    @NotNull
    private static String getAggregatedNames(@NotNull PrivilegeDefinition definition, @NotNull NameResolver nameResolver) {
        Set<Name> aggregatedNames = definition.getDeclaredAggregateNames();
        if (aggregatedNames.isEmpty()) {
            return "";
        } else {
            Set<String> names = aggregatedNames.stream().map(name -> {
                try {
                    return nameResolver.getJCRName(name);
                } catch (NamespaceException e) {
                    throw new IllegalStateException(e);
                }
            }).collect(Collectors.toSet());
            return " with "+String.join(",", names);
        }
    }
}
