package com.atlassian.bitbucket.internal.ssh.who;

import com.atlassian.bitbucket.auth.AuthenticationContext;
import com.atlassian.bitbucket.ssh.command.SshCommand;
import com.atlassian.bitbucket.ssh.command.SshCommandFactory;
import com.google.common.collect.ImmutableSet;

import javax.annotation.Nonnull;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;

import static java.util.Optional.empty;
import static java.util.Optional.of;

/**
 * Adds support for a selection of "who am I" commands. These are primarily intended to facilitate support by allowing
 * users to SSH into the system and ask it to echo back the user it loaded for their key. For users with multiple user
 * accounts on the system, this can be useful when, for example, tracking down permission-related issues.
 */
public class WhoAmISshCommandFactory implements SshCommandFactory {

    /**
     * A selection of different syntaxes for "who am I" commands.
     */
    private static final Set<String> SUPPORTED_COMMANDS = ImmutableSet.of("who am i", "whoami", "who");

    private final AuthenticationContext authenticationContext;

    public WhoAmISshCommandFactory(AuthenticationContext authenticationContext) {
        this.authenticationContext = authenticationContext;
    }

    /**
     * Creates a new {@link WhoAmISshCommand} if the provided {@code command} matches one of the
     * {@link #SUPPORTED_COMMANDS supported "who am I" commands}. Otherwise, for any other command, returns
     * {@link Optional#empty empty}.
     *
     * @param command the command String passed from the remote SSH client (e.g. "git upload-pack path/to/repository")
     * @param stdin   the {@code InputStream} from the remote client
     * @param stdout  the {@code OutputStream} for writing output to the remote client
     * @param stderr  the error {@code OutputStream} for writing to the remote client's error stream
     * @return a {@link WhoAmISshCommand} or {@link Optional#empty empty} for unsupported commands
     */
    @Nonnull
    @Override
    public Optional<SshCommand> create(@Nonnull String command, @Nonnull InputStream stdin,
                                       @Nonnull OutputStream stdout, @Nonnull OutputStream stderr) {
        if (supports(command)) {
            return of(new WhoAmISshCommand(authenticationContext, stdout));
        }

        return empty();
    }

    public boolean supports(@Nonnull String command) {
        return SUPPORTED_COMMANDS.contains(command.toLowerCase(Locale.ROOT));
    }
}
