/**
 * Copyright (c) KMG. 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
 *
 */

if (project == rootProject) {
    // JDK 25 runtime profile shared by every SBK executable, generated
    // launcher, benchmark fork, and dashboard child process.
    //
    // ZGC keeps collection pauses independent of heap size and scales its
    // worker counts to the available CPUs. A 50% heap ceiling doubles the
    // default server-class heap allowance while preserving memory for native
    // SDK buffers, thread stacks, direct buffers, and the operating system.
    // Host-specific options such as AlwaysPreTouch, large pages, and fixed GC
    // thread counts intentionally remain operator overrides.
    def sbkPerformanceJvmArgs = [
            '-XX:+UseZGC',
            '-XX:+UseCompactObjectHeaders',
            '-XX:MaxRAMPercentage=50.0',
            '-XX:+DisableExplicitGC',
            '-XX:+ExitOnOutOfMemoryError'
    ]
    ext.sbkRuntimeJvmArgs = (sbkPerformanceJvmArgs + [
            '-Dsbk.runtimeJvmArgs=' + sbkPerformanceJvmArgs.join(',')
    ]).asImmutable()
}

plugins.withId('java') {
    apply plugin: 'java-library'
    apply plugin: 'checkstyle'
    apply plugin: 'jacoco'
    apply plugin: 'signing'

    // Configure Java toolchain
    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(25)
        }
    }

    // If SBK_JAVA_HOME or JAVA_HOME is set, configure the toolchain to use it
    def sbkJavaHome = System.getenv('SBK_JAVA_HOME') ?: System.getenv('JAVA_HOME')
    if (sbkJavaHome != null && !sbkJavaHome.isEmpty()) {
        javaToolchains {
            launcherFor {
                languageVersion = JavaLanguageVersion.of(25)
            }
        }
        tasks.withType(JavaCompile).configureEach {
            options.fork = true
            options.forkOptions.javaHome = file(sbkJavaHome)
        }
        tasks.withType(Test).configureEach {
            executable = file("${sbkJavaHome}/bin/java")
        }
    }

    // Validate Java version
    def currentJavaVersion = JavaVersion.current()
    def expectedJavaVersion = JavaVersion.VERSION_25

    if (currentJavaVersion != expectedJavaVersion) {
        throw new GradleException(
            "Java version mismatch! Expected: ${expectedJavaVersion}, but found: ${currentJavaVersion}. " +
            "Please install Java ${expectedJavaVersion.majorVersion} and set SBK_JAVA_HOME or JAVA_HOME appropriately."
        )
    }

    java {
        sourceCompatibility = expectedJavaVersion
        targetCompatibility = expectedJavaVersion
    }


    compileJava {
        options.compilerArgs.addAll([
                "-Xlint:deprecation",
                "-Xlint:divzero",
                "-Xlint:empty",
                "-Xlint:fallthrough",
                "-Xlint:finally",
                "-Xlint:overrides",
                "-Xlint:path"
        ])
    }

    // Driver configuration fields are commonly documented in their properties
    // files, so drivers tolerate missing comments. Core modules keep every
    // doclint check enabled because they define SBK's public APIs.
    tasks.withType(Javadoc).configureEach {
        def doclintChecks = project.path.startsWith(':drivers:')
                ? 'all,-missing'
                : 'all'
        options.addBooleanOption("Xdoclint:${doclintChecks}", true)
        if (project.path == ':sbk-api') {
            exclude 'io/sbp/grpc/**'
        }
    }

    tasks.register('sourcesJar', Jar) {
        duplicatesStrategy = DuplicatesStrategy.EXCLUDE
        archiveClassifier = 'sources'
        from sourceSets.main.java
    }

    assemble.dependsOn(sourcesJar)

    tasks.register('generateJavadoc', Javadoc) {
        source = sourceSets.main.allJava
        classpath = sourceSets.main.runtimeClasspath
        failOnError = true
    }

    tasks.register('javadocJar', Jar) {
        archiveClassifier = 'javadoc'
        exclude "**/generated/**"
        from generateJavadoc
    }

    assemble.dependsOn(javadocJar)

    tasks.register('testJar', Jar) {
        archiveClassifier = 'tests'
        from sourceSets.test.output
    }

    assemble.dependsOn(testJar)

    if (project.hasProperty("doSigning")) {
        signing {
            sign configurations.archives
        }
        // Default the secretKeyRingFile to the current user's home
        if (!project.property("signing.secretKeyRingFile")) {
            def secretKeyPath = project.file("${System.getProperty("user.home")}/.gnupg/secring.gpg").absolutePath
            project.setProperty("signing.secretKeyRingFile", secretKeyPath)
        }
    }

    tasks.withType(Test) {
        systemProperties 'logback.configurationFile': new File(buildDir, 'resources/test/logback.xml').absolutePath
        testLogging.showStandardStreams = false
        testLogging.exceptionFormat = "FULL"
        testLogging.showCauses = true
        testLogging.showExceptions = true
        testLogging.showStackTraces = true
        testLogging.events = ["PASSED", "FAILED"]
        maxParallelForks = System.properties['maxParallelForks'] ? System.properties['maxParallelForks'].toInteger() : 1
        minHeapSize = "128m"
        maxHeapSize = "512m"
        
        // Use JUnit 5 platform for test discovery and execution
        useJUnitPlatform()
    }

    dependencies {
        // The production code uses the SLF4J logging API at api time
        api "org.slf4j:slf4j-api:$slf4jVersion"
        api "org.junit.jupiter:junit-jupiter-api:$junitVersion"
        api "org.mockito:mockito-core:${mockitoVersion}"
        
        // JUnit 5 test engine and runtime for test discovery and execution
        testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
        testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
        testImplementation "org.junit.platform:junit-platform-launcher"
    }
}
