package com.blackduck.integration.detectable.detectables.git.cli;

import java.io.File;
import java.net.MalformedURLException;
import java.util.Optional;

import org.slf4j.LoggerFactory;

import com.blackduck.integration.blackduck.bdio2.model.GitInfo;
import com.blackduck.integration.detectable.ExecutableTarget;
import com.blackduck.integration.detectable.detectables.git.GitUrlParser;
import com.blackduck.integration.detectable.extraction.Extraction;
import com.blackduck.integration.detectable.extraction.ExtractionMetadata;
import com.blackduck.integration.detectable.util.ToolVersionLogger;
import com.blackduck.integration.exception.IntegrationException;
import com.blackduck.integration.executable.ExecutableRunnerException;
import com.blackduck.integration.log.IntLogger;
import com.blackduck.integration.log.Slf4jIntLogger;

public class GitCliExtractor {
    public static final ExtractionMetadata<GitInfo> EXTRACTION_METADATA_KEY = new ExtractionMetadata<>("gitInfo", GitInfo.class);

    private final IntLogger logger = new Slf4jIntLogger(LoggerFactory.getLogger(this.getClass()));

    private final GitUrlParser gitUrlParser;
    private final ToolVersionLogger toolVersionLogger;
    private final GitCommandRunner gitCommandRunner;

    public GitCliExtractor(GitUrlParser gitUrlParser, ToolVersionLogger toolVersionLogger, GitCommandRunner gitCommandRunner) {
        this.gitUrlParser = gitUrlParser;
        this.toolVersionLogger = toolVersionLogger;
        this.gitCommandRunner = gitCommandRunner;
    }

    public Extraction extract(ExecutableTarget gitExecutable, File directory) {
        try {
            toolVersionLogger.log(directory, gitExecutable);

            String remoteUrl = gitCommandRunner.getRepoUrl(gitExecutable, directory);
            remoteUrl = gitUrlParser.removeCredentialsFromUri(remoteUrl);
            String repoName = gitUrlParser.getRepoName(remoteUrl);

            Optional<String> branch = Optional.ofNullable(gitCommandRunner.getRepoBranch(gitExecutable, directory));
            if (branch.isPresent() && "HEAD".equals(branch.get())) {
                logger.info("HEAD is detached for this repo, using heuristics to find Git branch.");
                branch = gitCommandRunner.getRepoBranchBackup(gitExecutable, directory);
            }

            String commitHash = gitCommandRunner.getCommitHash(gitExecutable, directory);

            GitInfo gitInfo = new GitInfo(remoteUrl, commitHash, branch.orElse(null));

            return new Extraction.Builder()
                .success()
                .metaData(EXTRACTION_METADATA_KEY, gitInfo)
                .projectName(repoName)
                .projectVersion(branch.orElse(commitHash))
                .build();
        } catch (ExecutableRunnerException | IntegrationException | MalformedURLException e) {
            logger.debug("Failed to extract project info from the git executable.", e);
            return new Extraction.Builder()
                .success()
                .build();
        }
    }

}
