import groovy.json.*
import java.util.*

IMAGES_DIR = 'images'
TAG_REST_ENDPOINT = "https://api.github.com/repos/${DEBEZIUM_REPOSITORY}/tags"
STREAMS_TO_BUILD_COUNT = STREAMS_TO_BUILD_COUNT.toInteger()
TAGS_PER_STREAM_COUNT = TAGS_PER_STREAM_COUNT.toInteger()
GIT_CREDENTIALS_ID = 'debezium-github'
DOCKER_CREDENTIALS_ID = 'debezium-dockerhub'

class Version implements Comparable {
    int major
    int minor
    int micro
    String classifier

    def Version(major, minor) {
        this.major = major
        this.minor = minor
        this.micro = -1
    }

    Version(name) {
        def parts = name.split('\\.')
        major = Integer.parseInt(parts[0])
        minor = Integer.parseInt(parts[1])
        micro = Integer.parseInt(parts[2])
        classifier = parts[3]
    }

    @NonCPS
    def majorMinor() {
        new Version(major, minor)
    }

    @Override
    @NonCPS
    def String toString() {
        def sb = new StringBuilder()
        if (major != -1) {
            sb.append(major)
        }
        if (minor != -1) {
            sb.append('.')
            sb.append(minor)
        }
        if (micro != -1) {
            sb.append('.')
            sb.append(micro)
        }
        if (classifier != null) {
            sb.append('.')
            sb.append(classifier)
        }
        sb.toString()
    }

    @Override
    @NonCPS
    boolean equals(o) {
        (o == null) ? false : toString() == o.toString()
    }

    @Override
    @NonCPS
    int hashCode() {
        toString().hashCode()
    }

    @Override
    @NonCPS
    int compareTo(o) {
        int d = major - o.major
        if (d != 0) {
            return d
        }
        d = minor - o.minor
        if (d != 0) {
            return d
        }
        d = micro - o.micro
        if (d != 0) {
            return d
        }
        if (classifier != null) {
            return classifier.compareTo(o.classifier)
        }
        return 0
    }
}

// Map keyed by stream - e.g 1.5 and containing a list of tags per-stream
versions = [:] as TreeMap

// The most recent streams to be built
streamsToBuild = null

// The most resent stable stream representing latest tag
stableStream = null

@NonCPS
def initVersions() {
    TAG_REST_ENDPOINT.toURL().openConnection().with {
        doOutput = true
        setRequestProperty('Content-Type', 'application/json')
        def json = new JsonSlurper().parse(new StringReader(content.text))
        json.each {
            def current = new Version(it.name.substring(1))
            def stream = current.majorMinor()
            versionList = versions[stream]
            if (versionList == null) {
                versionList = []
                versions[stream] = versionList
            }
            versionList.add(current)
        }
    }

    echo "Versions: $versions"
    // Order the tags per stream form the most recent one
    versions.each { k, v ->
        Collections.sort(v)
        Collections.reverse(v)
    }

    // Find the most recent streams and the latest stable
    streamsToBuild = [versions.lastKey()]
    for (int i = 1; i < STREAMS_TO_BUILD_COUNT; i++) {
        streamsToBuild.add(versions.lowerKey(streamsToBuild[-1]))
    }
    stableStream = streamsToBuild.find {
        def tags = versions[it]
        tags.size() > 0 && tags[0].classifier == 'Final'
    }
}

node('Slave') {
    try {
        stage('Initialize') {
            dir('.') {
                deleteDir()
            }
            checkout([$class                           : 'GitSCM',
                      branches                         : [[name: IMAGES_BRANCH]],
                      doGenerateSubmoduleConfigurations: false,
                      extensions                       : [[$class: 'RelativeTargetDirectory', relativeTargetDir: IMAGES_DIR]],
                      submoduleCfg                     : [],
                      userRemoteConfigs                : [[url: "https://$IMAGES_REPOSITORY", credentialsId: GIT_CREDENTIALS_ID]]
            ]
            )
            initVersions()
            withCredentials([usernamePassword(credentialsId: DOCKER_CREDENTIALS_ID, passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
                sh """
                    docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
                """
            }
        }
        stage('master') {
            echo "Building images for streams $streamsToBuild"
            dir(IMAGES_DIR) {
                sh "PUSH_IMAGES=true DEBEZIUM_VERSIONS=\"${streamsToBuild.join(' ')}\" LATEST_STREAM=\"$stableStream\" ./build-all.sh"
            }
        }
        for (stream in streamsToBuild) {
            for (tag in versions[stream].take(TAGS_PER_STREAM_COUNT)) {
                echo "Building images for tag $tag"
                stage(tag.toString()) {
                    dir(IMAGES_DIR) {
                        sh """
                            git checkout v$tag
                            git fetch origin $IMAGES_BRANCH:$IMAGES_BRANCH
                            git checkout $IMAGES_BRANCH build-all.sh build-debezium.sh build-mongo.sh build-postgres.sh
                            PUSH_IMAGES=true RELEASE_TAG=$tag ./build-debezium.sh $stream
                            git reset --hard
                        """
                    }
                }
            }
        }
    } finally {
        mail to: 'jpechane@redhat.com', subject: "${JOB_NAME} run #${BUILD_NUMBER} finished", body: "Run ${BUILD_URL} finished with result: ${currentBuild.currentResult}"
    }
}
