package com.atlassian.bitbucket.internal.importer.web;

import com.atlassian.bitbucket.internal.importer.repository.ImportTaskState;
import com.atlassian.bitbucket.internal.importer.repository.RepositoryImportService;
import com.atlassian.bitbucket.internal.importer.repository.RepositoryImportTask;
import com.atlassian.bitbucket.nav.NavBuilder;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.repository.RepositoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;

import static com.atlassian.bitbucket.internal.importer.repository.ImportTaskState.FAILED;
import static com.atlassian.bitbucket.internal.importer.repository.ImportTaskState.SUCCESS;
import static java.util.Optional.empty;
import static java.util.Optional.ofNullable;

@Component
public class RepositoryImportFilter implements Filter {
    private static final String PROJECTS = "projects";
    private static final String REPOS = "repos";
    private static final String SETTINGS = "settings";
    private final NavBuilder navBuilder;
    private final RepositoryImportService repositoryImportService;
    private final RepositoryService repositoryService;

    @Autowired
    public RepositoryImportFilter(@Qualifier("navBuilder") NavBuilder navBuilder,
                                  @Qualifier("repositoryImportService") RepositoryImportService repositoryImportService,
                                  @Qualifier("repositoryService") RepositoryService repositoryService) {
        this.repositoryImportService = repositoryImportService;
        this.repositoryService = repositoryService;
        this.navBuilder = navBuilder;
    }

    @Override
    public void destroy() {
        // Noop
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        if ("GET".equals(httpServletRequest.getMethod())) {
            Optional<Repository> maybeRepository = getPathParts(httpServletRequest)
                    .filter(this::isRepoPath)
                    .flatMap(this::getRepository);
            if (maybeRepository.isPresent()) {
                Repository repository = maybeRepository.get();
                Optional<ImportTaskState> importTaskState = repositoryImportService
                        .getRepositoryImportTask(repository)
                        .map(RepositoryImportTask::getState);
                // If the import task is not in a "finished" state, redirect.
                if (importTaskState.map(state -> state != SUCCESS && state != FAILED).orElse(false)) {
                    ((HttpServletResponse) response).sendRedirect(navBuilder.pluginServlets().path("import-in-process",
                            "projects", repository.getProject().getKey(),
                            "repos", repository.getSlug()).buildRelative());
                    return;
                }
            }
        }
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // Noop
    }

    private Optional<String[]> getPathParts(HttpServletRequest httpRequest) {
        String pathInfo = httpRequest.getPathInfo();
        if (pathInfo == null || pathInfo.isEmpty()) {
            return empty();
        }
        return Optional.of(pathInfo
                .substring(1) // to get rid of the leading slash
                .split("/"));
    }

    private Optional<Repository> getRepository(String[] pathParts) {
        return isRepoPath(pathParts) ?
                ofNullable(repositoryService.getBySlug(pathParts[1], pathParts[3])) : empty();
    }

    private boolean isRepoPath(String[] pathParts) {
        return pathParts.length > 3 && PROJECTS.equals(pathParts[0]) && REPOS.equals(pathParts[2]);
    }
}
