import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
import org.yaml.snakeyaml.Yaml

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath group: 'org.yaml', name: 'snakeyaml', version: '2.4'
    }
}

plugins {
    id 'org.jetbrains.kotlin.jvm'
    id 'application'
    id 'com.google.protobuf' version '0.9.4'
    id 'org.panteleyev.jpackageplugin' version '1.6.1'
    id("io.freefair.compress.7z") version "8.13.1"
}


repositories {
    mavenCentral()
}


tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

group = 'net.gaminik'


def grpcVersion = '1.71.0'
def protobufVersion = '3.25.5'

dependencies {
    implementation "io.grpc:grpc-protobuf:${grpcVersion}"
    implementation "io.grpc:grpc-stub:${grpcVersion}"
    implementation "io.grpc:grpc-services:${grpcVersion}"
    implementation "io.grpc:grpc-protobuf-lite:${grpcVersion}"
    implementation "io.grpc:grpc-netty-shaded:${grpcVersion}"
    // https://mvnrepository.com/artifact/io.perfmark/perfmark-api
    implementation 'io.perfmark:perfmark-api:0.27.0'
    compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+

    // https://mvnrepository.com/artifact/commons-codec/commons-codec
    implementation 'commons-codec:commons-codec:1.18.0'
    // https://mvnrepository.com/artifact/commons-io/commons-io
    implementation 'commons-io:commons-io:2.19.0'
    // https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
    implementation("org.bouncycastle:bcprov-jdk15on:1.70")
    implementation 'org.yaml:snakeyaml:2.4'
    implementation 'org.apache.commons:commons-lang3:3.12.0'
    // https://mvnrepository.com/artifact/org.slf4j/slf4j-api
    implementation 'org.slf4j:slf4j-api:2.0.17'
    // 1.4.x requires JDK 11
    implementation 'ch.qos.logback:logback-classic:1.3.15'
    // https://mvnrepository.com/artifact/com.google.code.gson/gson
    implementation 'com.google.code.gson:gson:2.13.0'

    // https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
    implementation 'com.squareup.okhttp3:okhttp:4.12.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
    // https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp-sse
    implementation group: 'com.squareup.okhttp3', name: 'okhttp-sse', version: '4.12.0'
    // https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-kotlin
    implementation 'com.fasterxml.jackson.module:jackson-module-kotlin:2.18.3'
    implementation 'io.github.haibiiin:json-repair:0.3.0'
    // https://mvnrepository.com/artifact/org.json/json
    implementation group: 'org.json', name: 'json', version: '20250107'


    testImplementation 'org.junit.jupiter:junit-jupiter:5.12.2'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    testImplementation "io.grpc:grpc-testing:${grpcVersion}"
    testImplementation "io.grpc:grpc-inprocess:${grpcVersion}"
    testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1"

}

test {
    useJUnitPlatform()
}


var archiveBaseName = 'GTransAgent'

def internalConfig = new Yaml().loadAll(new File("$projectDir/src/main/resources/internal.yaml").newInputStream()).first()

def versionForJpackage = internalConfig['agentVersionName']
version = "v" + internalConfig['agentVersionName']

//version = '1.0' //Error: Invalid version number: 1.0-SNAPSHOT (only '0'-'9' and '.' allowed)
println("version: " + version)

application {
    mainClassName = 'net.gtransagent.GTransAgentServer'
}

protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:${protobufVersion}"
    }
    plugins {
        grpc {
            artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
        }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
        }
    }
}


task fatJar(type: Jar) {
    outputs.upToDateWhen { false }
    // do't delete this line, it is necessary for gradle to not delete the directory
    outputs.dir("${buildDir}/libs")

    duplicatesStrategy = DuplicatesStrategy.EXCLUDE

    exclude('**/MANIFEST.MF')
    exclude('**/MSFTSIG.RSA')
    exclude('**/*.SF')
    exclude('**/*.DSA')
    exclude('editable')
    exclude('*.proto')
    exclude('*.sh')

    manifest {
        attributes 'Main-Class': "${mainClassName}"
    }
    archiveBaseName = "${archiveBaseName}"
    from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } }

    with jar
}

var distributionDir = 'distributions'

// copy editable config files to libs
task copyEditableConfigFile(type: Copy) {
    from('src/main/resources/editable')
    into "${buildDir}/libs"
}

// copy script files
task copyScriptFiles(type: Copy) {
    from('src/main/resources')
    include 'run.sh'
    include 'run.bat'
    excludes = [
            "editable/**",
            "*.proto",
            "internal.yaml"
    ]
    into "${buildDir}/libs"
    expand([
            version: version,
    ])
}

// need to install jdk 17, and set JAVA_HOME to jdk 17,
// jpackage --type app-image --name GTransAgent --input libs --main-jar GTransAgent-1.0.jar --win-console --dest distributions
tasks.jpackage {
    dependsOn("fatJar")

    outputs.upToDateWhen { false }
    // do't delete this line, it is necessary for gradle to not delete the directory
    outputs.dir("$buildDir/$distributionDir")

    input = "$buildDir/libs"

    if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) {
        // mac osx, add subdir
        destination = "$buildDir/$distributionDir/$archiveBaseName"
    }else{
        destination = "$buildDir/$distributionDir"
    }

    appName = "${archiveBaseName}"
    appVersion = "${versionForJpackage}"
    vendor = "${archiveBaseName}"

    type = "app-image"

    mainJar = "${archiveBaseName}-${version}.jar"
    mainClassName = "${mainClassName}"

    removeDestination = true
    javaOptions = ["-Dfile.encoding=UTF-8", "-Xms256m",
                   "-Xmx1024m"]

    icon = "icons/icon.ico"
    windows {
        winConsole = true
    }

    mac {
        icon = "icons/icon.icns"
    }
}

// copy editable config files to jpackage directory
task copyEditableConfigsToJpackage(type: Copy) {
    dependsOn("jpackage")
    from('src/main/resources/editable')
    into "$buildDir/$distributionDir/${archiveBaseName}"
}

// copy editable config files to jpackage directory, for mac
task copyEditableConfigsToJpackageForMac(type: Copy) {
    dependsOn("jpackage")
    from('src/main/resources/editable')
    into "$buildDir/$distributionDir/${archiveBaseName}"
}

// for windows
task packageJpackageZipArchive(type: Zip) {
    dependsOn("copyEditableConfigsToJpackage")

    var osArch = getOsArch()
    archiveFileName = "${archiveBaseName}-bin-${version}-${osArch}.zip"
    destinationDirectory = file("${rootProject}/../releases/")

    from("$buildDir/$distributionDir/${archiveBaseName}") {
    }
}

// for mac
task packageJpackageZipArchiveForMac(type: Zip) {
    dependsOn("copyEditableConfigsToJpackageForMac")

    var osArch = getOsArch()
    archiveFileName = "${archiveBaseName}-bin-${version}-${osArch}.zip"
    destinationDirectory = file("${rootProject}/../releases/")

    from("$buildDir/$distributionDir") {
    }
}

// for linux
task packageJpackageZipArchiveForLinux(type: Zip) {
    dependsOn("copyEditableConfigsToJpackage")

    var osArch = getOsArch()
    archiveFileName = "${archiveBaseName}-bin-${version}-${osArch}.zip"
    destinationDirectory = file("${rootProject}/../releases/")

    from("$buildDir/$distributionDir") {
    }
}

// package jar and zip archive
task packageJarZipArchive(type: Zip) {
    dependsOn("fatJar")
    dependsOn("copyEditableConfigFile")
    dependsOn("copyScriptFiles")

    archiveFileName = "${archiveBaseName}-bin-${version}-jar.zip"
    destinationDirectory = file("${rootProject}/../releases/")

    from("$buildDir/libs") {
        //add subdir
        into("$archiveBaseName")
    }
}

def getOsArch() {
    def arch = DefaultNativePlatform.currentArchitecture
    def name = (DefaultNativePlatform.currentOperatingSystem.name + "-" + arch.name.toLowerCase())
    if (org.gradle.internal.os.OperatingSystem.current().isWindows()) {
        name = ("win-" + arch.name.toLowerCase())
    } else if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) {
        name = ("mac-" + arch.name.toLowerCase())
    } else if (org.gradle.internal.os.OperatingSystem.current().isLinux()) {
        name = ("linux-" + arch.name.toLowerCase())
    }
    println("arch: " + arch + ", name: " + name)
    return name
}