import javax.inject.Inject
import org.gradle.api.provider.ValueSourceParameters
import java.nio.charset.Charset

ext {

    buildVersionCode = {
        def versionCode = buildNumberCode()
        def versionName = getVersionName()
        def (major, minor, patch) = versionName.toLowerCase().tokenize('.')
        (major, minor, patch) = [major, minor, patch].collect { it.toInteger() }
        (major * 10_000_000) + (minor * 10_000) + (patch * 1_000) + versionCode
    }

    getVersionName = {
        def props = new Properties()
        file("$rootDir/app/version/version.properties").withInputStream { props.load(it) }
        return props.getProperty("VERSION")
    }

    getVersionNameSuffix = {
        if (project.hasProperty("versionNameSuffix")) {
            return project["versionNameSuffix"]
        } else {
            return ""
        }
    }

    buildVersionName = {
        def suffix = getVersionNameSuffix()
        if (suffix?.trim()) {
            return getVersionName() + "." + buildNumberCode() + getVersionNameSuffix()
        } else {
            return getVersionName()
        }
    }

    getStoredTag = {
        if(project.hasProperty("latestTag")) {
            return project["latestTag"]
        } else {
            def latestGitTagProvider = providers.of(LatestGitTagValueSource.class) {}
            return latestGitTagProvider.get()
        }
    }

    buildNumberCode = {
        def suffix = getVersionNameSuffix()
        if (suffix?.trim()) {
            def tag = getStoredTag()
            if (tag.contains('nightly') || tag.contains('internal')) {
                def (major, minor, patch, internal) = tag.toLowerCase().tokenize('.')
                (major, minor, patch, internal) = [major, minor, patch, internal].collect { it.toString() }

                def (code, sufix) = internal.toLowerCase().tokenize('-')
                (code, sufix) = [code, sufix].collect { it.toString() }

                def newCode = Integer.parseInt(code) + 1
                return newCode
            } else {
                return 1
            }
        } else {
            return 0
        }
    }
}

tasks.register("setBuildNumber") {
    doLast {
        if(!project.hasProperty("number")) {
            throw new IllegalArgumentException("Missing argument: 'number' must be provided")
        }

        filePath = "${CI_HOME_DIR}/build_number.properties"
        if(!new File(filePath).exists()) {
            throw new IllegalStateException("build number file could not be found at: $filePath")
        }

        String buildNumberString = project["number"]
        Integer buildNumberInt = Integer.parseInt(buildNumberString)
        if(buildNumberInt >= 1000) {
            throw new IllegalStateException("Build number limited to 3 digits; cannot exceed 1,000")
        }
        println("Setting build number to: $buildNumberInt")

        def props = new Properties()
        props.load(new FileInputStream(filePath))
        props["build"] = buildNumberInt.toString()
        def os = new FileOutputStream(filePath)
        props.store(os, null)
    }
}

tasks.register('incrementBuildNumber') {
    doLast {
        filePath = "${CI_HOME_DIR}/build_number.properties"
        if(!new File(filePath).exists()) {
            return
        }

        def props = new Properties()
        props.load(new FileInputStream(filePath))
        String currentBuildNumber = props["build"]
        Integer buildNumber = Integer.parseInt(currentBuildNumber)
        buildNumber++
        if(buildNumber >= 1000) {
            throw new IllegalStateException("Build number limited to 3 digits; cannot exceed 1,000")
        }
        props["build"] = buildNumber.toString()
        def os = new FileOutputStream(filePath)
        props.store(os, null)
    }
}

tasks.register('getBuildVersionName') {
    doLast {
        print buildVersionName()
    }
}

tasks.register('getBuildVersionCode') {
    doLast {
        print buildNumberCode()
    }
}

abstract class LatestGitTagValueSource implements ValueSource<String, ValueSourceParameters.None> {
    @Inject
    abstract ExecOperations getExecOperations()

    String obtain() {
        ByteArrayOutputStream output = new ByteArrayOutputStream()
        execOperations.exec {
            it.commandLine "git", "describe", "--tags", "--abbrev=0"
            it.standardOutput = output
        }
        return new String(output.toByteArray(), Charset.defaultCharset())
    }
}