package io.freefair.gradle.plugins.git;

import org.codehaus.groovy.runtime.ProcessGroovyMethods;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.logging.Logger;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GitVersionPlugin implements Plugin<Project> {

    private static final Pattern releaseBranchPattern = Pattern.compile("release-(\\d+.*)");
    private static final Pattern hotfixBranchPattern = Pattern.compile("hotfix-(\\d+.*)");
    private static final Pattern vTagPattern = Pattern.compile("v(\\d+.*)");

    private Project project;
    private Logger logger;

    @Override
    public void apply(Project project) {
        this.project = project;
        this.logger = project.getLogger();
        project.setVersion(resolveVersion());

        project.allprojects(p -> p.setVersion(project.getVersion()));
    }

    protected String resolveBranchVersion(String branch) {
        String baseVersion = branch;

        Matcher matcher = releaseBranchPattern.matcher(branch);
        if (matcher.matches()) {
            baseVersion = matcher.group(1);
        }

        matcher = hotfixBranchPattern.matcher(branch);
        if (matcher.matches()) {
            baseVersion = matcher.group(1);
        }

        baseVersion = baseVersion.replace("/", "-");

        return baseVersion + "-SNAPSHOT";
    }

    protected String resolveTagVersion(String tag) {
        String version = tag;

        Matcher matcher = vTagPattern.matcher(tag);
        if (matcher.matches()) {
            version = matcher.group(1);
        }

        return version;
    }

    private Object resolveVersion() {
        if (!"unspecified".equals(project.getVersion().toString())) {
            logger.lifecycle("Using explicit version {}", project.getVersion());
            return project.getVersion();
        }

        if (isTravisCi()) {
            String travisTag = System.getenv("TRAVIS_TAG");
            if (travisTag != null && !travisTag.trim().isEmpty()) {
                String version = resolveTagVersion(travisTag);
                logger.lifecycle("Using TRAVIS_TAG '{}' as version: {}", travisTag, version);
                return version;
            }

            String travisBranch = System.getenv("TRAVIS_BRANCH");
            if (travisBranch != null) {
                String version = resolveBranchVersion(travisBranch);
                logger.lifecycle("Using TRAVIS_BRANCH '{}' as version: {}", travisBranch, version);
                return version;
            }
        }
        else if (isGithubActions()) {
            String githubRef = System.getenv("GITHUB_REF");
            if (githubRef != null) {
                if (githubRef.startsWith("refs/tags/")) {
                    githubRef = githubRef.substring("refs/tags/".length());
                    String version = resolveTagVersion(githubRef);
                    logger.lifecycle("Using GitHub Tag '{}' as version: {}", githubRef, version);
                    return version;
                }
                else if (githubRef.startsWith("refs/heads/")) {
                    githubRef = githubRef.substring("refs/heads/".length());
                    String version = resolveBranchVersion(githubRef);
                    logger.lifecycle("Using GitHub Branch '{}' as version: {}", githubRef, version);
                    return version;
                }
            }
        }

        try {
            Process execute = ProcessGroovyMethods.execute("git describe --tags --exact-match");
            String gitTag = ProcessGroovyMethods.getText(execute).trim();

            if (!gitTag.isEmpty()) {
                String version = resolveTagVersion(gitTag);
                logger.lifecycle("Using git tag '{}' as version: {}", gitTag, version);
                return gitTag;
            }
        } catch (Exception e) {
            logger.debug("Failed to get current git tag", e);
        }

        if (isJenkins()) {
            String gitLocalBranch = System.getenv("GIT_LOCAL_BRANCH");
            if (gitLocalBranch != null && !gitLocalBranch.isEmpty()) {
                String version = resolveBranchVersion(gitLocalBranch);
                logger.lifecycle("Using GIT_LOCAL_BRANCH '{}' as version: {}", gitLocalBranch, version);
                return version;
            }
            String gitBranch = System.getenv("GIT_BRANCH");
            if (gitBranch != null && !gitBranch.isEmpty()) {
                String version = resolveBranchVersion(gitBranch);
                logger.lifecycle("Using GIT_BRANCH '{}' as version: {}", gitBranch, version);
                return version;
            }
            String branchName = System.getenv("BRANCH_NAME");
            if (branchName != null && !branchName.isEmpty()) {
                String version = resolveBranchVersion(branchName);
                logger.lifecycle("Using BRANCH_NAME '{}' as version: {}", branchName, version);
                return version;
            }
        }

        try {
            Process execute = ProcessGroovyMethods.execute("git symbolic-ref --short HEAD");
            String gitBranch = ProcessGroovyMethods.getText(execute).trim();

            if (!gitBranch.isEmpty()) {
                String version = resolveBranchVersion(gitBranch);
                logger.lifecycle("Using git branch '{}' as version: {}", gitBranch, version);
                return version;
            }
        } catch (Exception e) {
            logger.debug("Failed to get current git branch", e);
        }

        return project.getVersion();
    }

    private boolean isTravisCi() {
        return "true".equalsIgnoreCase(System.getenv("TRAVIS"));
    }

    private boolean isGithubActions() {
        return "true".equalsIgnoreCase(System.getenv("GITHUB_ACTIONS"));
    }

    private boolean isJenkins() {
        return System.getenv("JENKINS_HOME") != null;
    }
}

@@ -3436,32 +3436,728 @@
      %7D%0A        %7D
+%0A        else if (isCircleCi()) %7B%0A            String circleTag = System.getenv(%22CIRCLE_TAG%22);%0A            if (circleTag != null && !circleTag.trim().isEmpty()) %7B%0A                String version = resolveTagVersion(circleTag);%0A                logger.lifecycle(%22Using CIRCLE_TAG '%7B%7D' as version: %7B%7D%22, circleTag, version);%0A                return version;%0A            %7D%0A%0A            String circleBranch = System.getenv(%22CIRCLE_BRANCH%22);%0A            if (circleBranch != null) %7B%0A                String version = resolveBranchVersion(circleBranch);%0A                logger.lifecycle(%22Using CIRCLE_BRANCH '%7B%7D' as version: %7B%7D%22, circleBranch, version);%0A                return version;%0A            %7D%0A        %7D
 %0A%0A        try %7B%0A
@@ -6408,32 +6408,141 @@
 AVIS%22));%0A    %7D%0A%0A
+    private boolean isCircleCi() %7B%0A        return %22true%22.equalsIgnoreCase(System.getenv(%22CIRCLECI%22));%0A    %7D%0A%0A
     private bool

Add support for Circle-CI