/*
 * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
plugins {
    id 'jacoco'
}

apply plugin: 'java'

import org.apache.tools.ant.taskdefs.condition.Os

description = 'Ballerina - HTTP/WS Ballerina Tests'

def packageName = "http"
def packageOrg = "ballerina"
def moduleName = "tests"
def tomlVersion = stripBallerinaExtensionVersion("${project.version}")
def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/BallerinaTest.toml")
def testCommonTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/BallerinaTestCommon.toml")
def ballerinaDist = "${project.rootDir}/target/ballerina-runtime"
def distributionBinPath =  "${ballerinaDist}/bin"
def testCoverageParam = "--code-coverage --coverage-format=xml --includes=io.ballerina.stdlib.http.*:ballerina.http*"
def testPackages = ["http2-tests", "http-advanced-tests", "http-client-tests", "http-dispatching-tests",
                    "http-interceptor-tests", "http-misc-tests", "http-resiliency-tests", "http-security-tests",
                    "http-service-tests"]
def testCommonPackage = "http-test-common"

def stripBallerinaExtensionVersion(String extVersion) {
    if (extVersion.matches(project.ext.timestampedVersionRegex)) {
        def splitVersion = extVersion.split('-');
        if (splitVersion.length > 3) {
            def strippedValues = splitVersion[0..-4]
            return strippedValues.join('-')
        } else {
            return extVersion
        }
    } else {
        return extVersion.replace("${project.ext.snapshotVersion}", "")
    }
}

configurations {
    jbalTools
}

dependencies {
    jbalTools ("org.ballerinalang:jballerina-tools:${ballerinaLangVersion}") {
        transitive = false
    }
    implementation group: 'org.ballerinalang', name: 'toml-parser', version: "${ballerinaTomlParserVersion}"
}

clean {
    delete "${project.projectDir}/${testCommonPackage}/target"

    testPackages.each { testPackage ->
        delete "${project.projectDir}/${testPackage}/target"
    }
}

jar {
    manifest {
        attributes('Implementation-Title': project.name,
                'Implementation-Version': project.version)
    }
}

task updateTomlVersions {
    doLast {
        testPackages.each { testPackage ->
            def ballerinaTomlFile =  new File("${project.projectDir}/${testPackage}/Ballerina.toml")
            def newBallerinaToml = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version)
            newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion)
            newBallerinaToml = newBallerinaToml.replace("@test.common@", testCommonPackage.replaceAll("-", "_"))
            newBallerinaToml = newBallerinaToml.replace("@package.name@", testPackage.replaceAll("-", "_"))
            ballerinaTomlFile.text = newBallerinaToml
        }

        def ballerinaTomlFile =  new File("${project.projectDir}/${testCommonPackage}/Ballerina.toml")
        def newBallerinaToml = testCommonTomlFilePlaceHolder.text.replace("@project.version@", project.version)
        newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion)
        newBallerinaToml = newBallerinaToml.replace("@package.name@", testCommonPackage.replaceAll("-", "_"))
        ballerinaTomlFile.text = newBallerinaToml
    }
}

task commitTomlFiles {
    doLast {
        def files = "${testCommonPackage}/Ballerina.toml ${testCommonPackage}/Dependencies.toml "
        testPackages.each{ testPackage ->
            files += "${testPackage}/Ballerina.toml ${testPackage}/Dependencies.toml "
        }

        project.exec {
            ignoreExitValue true
            if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                commandLine 'cmd', '/c', "git commit -m \"[Automated] Update the native jar versions\" ${files}"
            } else {
                commandLine 'sh', '-c', "git commit -m '[Automated] Update the native jar versions' ${files}"
            }
        }
    }
}

def groupParams = ""
def disableGroups = ""
def windowsDisableGroups = "--disable-groups disabledOnWindows"
def debugParams = ""
def balJavaDebugParam = ""
def testParams = ""
def graalvmFlag = ""
def parallelTestFlag = ""
def skipTests = false

task initializeVariables {
    if (project.hasProperty("groups")) {
        groupParams = "--groups ${project.findProperty("groups")}"
    }
    if (project.hasProperty("disable")) {
        disableGroups = "--disable-groups ${project.findProperty("disable")}"
    }
    if (project.hasProperty("debug")) {
        debugParams = "--debug ${project.findProperty("debug")}"
    }
    if (project.hasProperty("balJavaDebug")) {
        balJavaDebugParam = "BAL_JAVA_DEBUG=${project.findProperty("balJavaDebug")}"
    }
    if (project.hasProperty('balGraalVMTest')) {
        graalvmFlag = '--graalvm'
    }
    if (project.hasProperty('balParallelTest')) {
        parallelTestFlag = '--parallel'
    }
    if (project.hasProperty('balTests')) {
        testPackages = project.findProperty('balTests').toString().split(",")
    }
    if (project.hasProperty('skipBalTests')) {
        project.findProperty('skipBalTests').toString().split(",").each {testPackage ->
            testPackages.remove(testPackage)
        }
    }


    gradle.taskGraph.whenReady { graph ->
        if (graph.hasTask(":${packageName}-ballerina-tests:test")) {
            if (!project.hasProperty('balGraalVMTest')) {
                testParams = "${testCoverageParam}"
            }
        } else {
            skipTests = true
        }
    }
}

task publishTestCommonPackageToLocal {
    dependsOn(":${packageName}-${packageOrg}:build")
    dependsOn(updateTomlVersions)
    doLast {
        if (!skipTests) {
            exec {
                workingDir "${project.projectDir}/${testCommonPackage}"
                if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                    commandLine 'cmd', '/c', "${distributionBinPath}/bal.bat pack && exit  %%ERRORLEVEL%%"
                } else {
                    commandLine 'sh', '-c', "${distributionBinPath}/bal pack"
                }
            }
            exec {
                workingDir "${project.projectDir}/${testCommonPackage}"
                if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                    commandLine 'cmd', '/c', "${distributionBinPath}/bal.bat push --repository=local" +
                            " && exit %%ERRORLEVEL%%"
                } else {
                    commandLine 'sh', '-c', "${distributionBinPath}/bal push --repository=local"
                }
            }
        }
    }
}

task ballerinaTest {
    inputs.dir file(project.projectDir)
    dependsOn(":${packageName}-${packageOrg}:build")
    dependsOn(updateTomlVersions)
    dependsOn(initializeVariables)
    dependsOn(":${packageName}-${packageOrg}-${moduleName}:compileJava")
    dependsOn(":${packageName}-${packageOrg}-${moduleName}:jar")
    dependsOn(":${packageName}-${packageOrg}-${moduleName}:processResources")
    dependsOn(publishTestCommonPackageToLocal)
    dependsOn(compileTestJava)
    dependsOn(processTestResources)
    finalizedBy(commitTomlFiles)

    doLast {
        testPackages.each { testPackage ->
            if (!skipTests) {
                exec {
                    workingDir "${project.projectDir}/${testPackage}"
                    environment "JAVA_OPTS", "-DBALLERINA_DEV_COMPILE_BALLERINA_ORG=true"
                    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                        commandLine 'cmd', '/c', "${balJavaDebugParam} ${distributionBinPath}/bal.bat test ${graalvmFlag}" +
                                " ${parallelTestFlag} ${testParams} ${groupParams} ${disableGroups} ${windowsDisableGroups}" +
                                "  ${debugParams} && exit %%ERRORLEVEL%%"
                    } else {
                        commandLine 'sh', '-c', "${balJavaDebugParam} ${distributionBinPath}/bal test ${graalvmFlag} " +
                                "${parallelTestFlag} ${testParams} ${groupParams} ${disableGroups} ${debugParams}"
                    }
                }
                if (project.hasProperty('balGraalVMTest')) {
                    exec {
                        workingDir "${project.projectDir}/${testPackage}"
                        environment "JAVA_OPTS", "-DBALLERINA_DEV_COMPILE_BALLERINA_ORG=true"
                        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                            commandLine 'cmd', '/c', "${distributionBinPath}/bal.bat clean"
                        } else {
                            commandLine 'sh', '-c', "${distributionBinPath}/bal clean"
                        }
                    }
                }
            }
        }
    }
}

publishing {
    repositories {
        maven {
            name = "GitHubPackages"
            url = uri("https://maven.pkg.github.com/ballerina-platform/module-${packageOrg}-${packageName}")
            credentials {
                username = System.getenv("packageUser")
                password = System.getenv("packagePAT")
            }
        }
    }
}

task startLdapServer() {
    doLast {
        // This check is added to prevent starting the server in Windows OS, since the Docker image does not support
        // for Windows OS.
        if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
            def stdOut = new ByteArrayOutputStream()
            exec {
                commandLine 'sh', '-c', "docker ps --filter name=openldap-server"
                standardOutput = stdOut
            }
            if (!stdOut.toString().contains("openldap-server")) {
                println "Starting LDAP server."
                exec {
                    commandLine 'sh', '-c', "docker compose -f $project.projectDir/resources/openldap/compose.yml up -d"
                    standardOutput = stdOut
                }
                println stdOut.toString()
                println "Waiting 15s until the LDAP server get initiated."
                sleep(15 * 1000)
            } else {
                println "LDAP server is already started."
            }
        }
    }
}

task stopLdapServer() {
    doLast {
        // This check is added to prevent trying to stop the server in Windows OS, since the Docker image not started
        // in Windows OS.
        if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
            def stdOut = new ByteArrayOutputStream()
            exec {
                commandLine 'sh', '-c', "docker ps --filter name=openldap-server"
                standardOutput = stdOut
            }
            if (stdOut.toString().contains("openldap-server")) {
                println "Stopping LDAP server."
                exec {
                    commandLine 'sh', '-c', "docker stop openldap-server"
                    standardOutput = stdOut
                }
                println stdOut.toString()
                println "Waiting 5s until the LDAP server get stopped."
                sleep(5 * 1000)
            } else {
                println "LDAP server is not started."
            }
        }
    }
}

task deleteDependencyTomlFile {
    if (project.hasProperty("deleteDependencies")) {
        delete "${project.projectDir}/${testCommonPackage}/Dependencies.toml"

        testPackages.each { testPackage ->
            delete "${project.projectDir}/${testPackage}/Dependencies.toml"
        }
    }
}

ballerinaTest.finalizedBy stopLdapServer
ballerinaTest.dependsOn startLdapServer
ballerinaTest.dependsOn deleteDependencyTomlFile
test.dependsOn ballerinaTest
build.dependsOn test
