buildscript {
    ext.kotlin_version_no = "1.8.21"
    ext.CI_PROJECT_ID = System.env.CI_PROJECT_ID

    repositories {
        mavenCentral()
    }
}

plugins {
    id "org.jetbrains.kotlin.jvm" version "$kotlin_version_no"
    id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version_no"
    id "java"
    id "java-test-fixtures"
}
apply plugin: "maven-publish"


version = "0.40.3-SNAPSHOT"
group = "org.domaindrivenarchitecture.provs"


repositories {
    mavenCentral()
}


java {
    // https://stackoverflow.com/questions/21904269/configure-gradle-to-publish-sources-and-javadoc
    withSourcesJar()
    withJavadocJar()

    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

test {
    // set properties for the tests
    def propertiesForTests = ["testdockerwithoutsudo"]
    for (def prop : propertiesForTests) {
        def value = System.getProperty(prop)
        if (value != null) {
            systemProperty prop, value
        }
    }

    useJUnitPlatform {
        def excludedTags = System.getProperty("excludeTags")
        if (System.getProperty("excludeTags") != null) {
            excludeTags(excludedTags.split(","))
        }
        if (System.getenv("CI_JOB_TOKEN") != null) {
            excludeTags("containernonci")
        }
    }
}

compileJava.options.debugOptions.debugLevel = "source,lines,vars"
compileTestFixturesJava.options.debugOptions.debugLevel = "source,lines,vars"
compileTestJava.options.debugOptions.debugLevel = "source,lines,vars"


dependencies {

    api("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version_no")
    api("org.jetbrains.kotlinx:kotlinx-cli:0.3.4")

    api('com.charleskorn.kaml:kaml:0.54.0')

    api("org.slf4j:slf4j-api:1.7.36")
    api('ch.qos.logback:logback-classic:1.4.14')
    api('ch.qos.logback:logback-core:1.4.14')

    implementation("com.hierynomus:sshj:0.38.0")

    testFixturesApi('io.mockk:mockk:1.12.3')

    testFixturesApi("org.junit.jupiter:junit-jupiter-api:5.8.2")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
}


tasks.register('uberjarDesktop', Jar) {

    from sourceSets.main.output

    dependsOn configurations.runtimeClasspath
    from {
        configurations.runtimeClasspath.findAll { it.name.endsWith("jar") }.collect { zipTree(it) }
    } {
        duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
        exclude "META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA"
    }

    manifest {
        attributes "Implementation-Title": "Uberjar of provs",
                "Implementation-Version": project.version,
                "Main-Class": "org.domaindrivenarchitecture.provs.desktop.application.ApplicationKt"
    }
    archiveFileName = "provs-desktop.jar"
}


tasks.register('uberjarServer', Jar) {

    from sourceSets.main.output

    dependsOn configurations.runtimeClasspath
    from {
        configurations.runtimeClasspath.findAll { it.name.endsWith("jar") }.collect { zipTree(it) }
    } {
        duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
        exclude "META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA"
    }

    manifest {
        attributes "Implementation-Title": "Uberjar of provs",
                "Implementation-Version": project.version,
                "Main-Class": "org.domaindrivenarchitecture.provs.server.application.ApplicationKt"
    }
    archiveFileName = "provs-server.jar"
}


tasks.register('uberjarSyspec', Jar) {

    from sourceSets.main.output

    dependsOn configurations.runtimeClasspath
    from {
        configurations.runtimeClasspath.findAll { it.name.endsWith("jar") }.collect { zipTree(it) }
    } {
        duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
        exclude "META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA"
    }

    manifest {
        attributes "Implementation-Title": "Uberjar of provs",
                "Implementation-Version": project.version,
                "Main-Class": "org.domaindrivenarchitecture.provs.syspec.application.ApplicationKt"
    }
    archiveFileName = "provs-syspec.jar"
}
def projectRoot = rootProject.projectDir


// copy jar to /usr/local/bin and make it executable
// Remark: to be able to use it you must have jarwrapper installed (sudo apt install jarwrapper)
tasks.register('installlocally') {
    dependsOn(uberjarServer, uberjarDesktop, uberjarSyspec)
    doLast {
        exec { commandLine("sh", "-c", "sudo apt-get update & sudo apt-get install jarwrapper") }
        exec { commandLine("sh", "-c", "sudo cp $projectRoot/build/libs/provs-server.jar /usr/local/bin/") }
        exec { commandLine("sh", "-c", "sudo cp $projectRoot/build/libs/provs-desktop.jar /usr/local/bin/") }
        exec { commandLine("sh", "-c", "sudo cp $projectRoot/build/libs/provs-syspec.jar /usr/local/bin/") }
        exec { commandLine("sh", "-c", "sudo chmod 755 /usr/local/bin/provs-server.jar") }
        exec { commandLine("sh", "-c", "sudo chmod 755 /usr/local/bin/provs-desktop.jar") }
        exec { commandLine("sh", "-c", "sudo chmod 755 /usr/local/bin/provs-syspec.jar") }
    }
}


// create binaries and install into /usr/local/bin
// PREREQUISITE: graalvm / native-image must be installed - see https://www.graalvm.org/
// NOTE: May take up tp 10 Min altogether!
tasks.register('binariesInstall') {
    dependsOn(uberjarServer, uberjarDesktop, uberjarSyspec)
    doLast {
        println "Building binaries ..."
        exec { commandLine("sh", "-c", "cd build/libs/ && native-image --no-fallback --initialize-at-build-time=kotlin.DeprecationLevel -H:+UnlockExperimentalVMOptions -H:IncludeResources=\".*org/domaindrivenarchitecture/provs/.*(conf|ssh_config|sshd_config|sh|vimrc|xml|yaml)\" -jar provs-desktop.jar") }
        exec { commandLine("sh", "-c", "cd build/libs/ && native-image --no-fallback --initialize-at-build-time=kotlin.DeprecationLevel -H:+UnlockExperimentalVMOptions -H:IncludeResources=\".*org/domaindrivenarchitecture/provs/.*(conf|ssh_config|sshd_config|sh|vimrc|xml|yaml)\" -jar provs-server.jar") }
        exec { commandLine("sh", "-c", "cd build/libs/ && native-image --no-fallback --initialize-at-build-time=kotlin.DeprecationLevel -H:+UnlockExperimentalVMOptions -H:IncludeResources=\".*org/domaindrivenarchitecture/provs/.*(conf|ssh_config|sshd_config|sh|vimrc|xml|yaml)\" -jar provs-syspec.jar") }
        exec { commandLine("sh", "-c", "sudo cp build/libs/provs-desktop /usr/local/bin/") }
        exec { commandLine("sh", "-c", "sudo cp build/libs/provs-server /usr/local/bin/") }
        exec { commandLine("sh", "-c", "sudo cp build/libs/provs-syspec /usr/local/bin/") }
    }
}


// publish to repo.prod.meissa.de with task "publishLibraryPublicationToMeissaRepository" -- (using pattern "publishLibraryPublicationTo<MAVEN REPOSITORY NAME>Repository")
publishing {
    publications {
        library(MavenPublication) {
            groupId 'org.domaindrivenarchitecture'
            artifactId 'provs'
            from components.java
        }
    }

    repositories {
        maven {
            name = "gitlab"
            url = "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/packages/maven"
            credentials(HttpHeaderCredentials) {
                name = "Job-Token"
                value = System.getenv("CI_JOB_TOKEN")
            }
            authentication {
                header(HttpHeaderAuthentication)
            }
        }
        maven {
            name = "meissa"
            url = uri("https://repo.prod.meissa.de/api/packages/meissa/maven")

            credentials(HttpHeaderCredentials) {
                name = "Authorization"
                def publishPackageTokenName = "MEISSA_PUBLISH_PACKAGE_TOKEN"
                if (System.getenv("CI_JOB_TOKEN") != null) {
                    def tokenFromEnv = System.getenv(publishPackageTokenName)
                    if (tokenFromEnv == null) {
                        println "Error: $publishPackageTokenName not found"
                    } else {
                        value = "token " + tokenFromEnv
                        println "$publishPackageTokenName found - "
                    }
                } else {
                    // for publishing from local: you must use project-property "MEISSA_PUBLISH_PACKAGE_TOKEN" with the token (e.g. define it in "~/.gradle/gradle.properties")
                    // you can create a token e.g. on forgejo server by "Profile and Settings ... > Settings > Applications", Token Name, Select scopes (write:package) > "Generate Token"
                    if (!project.hasProperty(publishPackageTokenName)) {
                        // if token is missing, provide a dummy in order to avoid error "Could not get unknown property ..." for Credentials [header: Authorization]" for other gradle tasks
                        ext.MEISSA_PUBLISH_PACKAGE_TOKEN = "Token $publishPackageTokenName not provided in file \".gradle/gradle.properties\""
                        println "Info: $publishPackageTokenName is set to a dummy value. In case of publishing to a maven repo, you will get a authorization error."
                    } else {
                        value = "token " + project.property(publishPackageTokenName)
                    }
                }
            }

            authentication {
                header(HttpHeaderAuthentication)
            }
        }
    }
}


// create version file to allow Kotlin code to print own version - see https://stackoverflow.com/questions/33020069/how-to-get-version-attribute-from-a-gradle-build-to-be-included-in-runtime-swing
tasks.register('createVersion') {
    dependsOn processResources
    doLast {
        def version = project.version.toString()
        def fileName = "src/main/resources/version.txt"
        def file = new File(fileName)
        file.write(version)
        println "Created file: " + fileName
    }
}

classes {
    dependsOn createVersion
}