import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
    id "java"
    id "org.jetbrains.kotlin.jvm" version "2.0.0"
    id "edu.wpi.first.GradleRIO" version "2025.3.1"
    id "com.diffplug.spotless" version "6.12.0"
    id "com.peterabeles.gversion" version "1.10"
    id 'com.google.devtools.ksp' version '2.0.0-1.0.21'
    id "idea"
}

def javaVersion = JavaVersion.VERSION_17

sourceSets {
    main {
        java {
            srcDirs += 'src/main/kotlin'
        }
    }
    test {
        java {
            srcDirs += 'src/test/kotlin'
        }
    }
}

java {
    sourceCompatibility = javaVersion
    targetCompatibility = javaVersion
}

def ROBOT_MAIN_CLASS = "frc.robot.Main"

// Define my targets (RoboRIO) and artifacts (deployable files)
// This is added by GradleRIO's backing project DeployUtils.
deploy {
    targets {
        roborio(getTargetTypeClass('RoboRIO')) {
            // Team number is loaded either from the .wpilib/wpilib_preferences.json
            // or from command line. If not found an exception will be thrown.
            // You can use getTeamOrDefault(team) instead of getTeamNumber if you
            // want to store a team number in this file.
            team = project.frc.getTeamNumber()
            debug = project.frc.getDebugOrDefault(false)

            artifacts {
                // First part is artifact name, 2nd is artifact type
                // getTargetTypeClass is a shortcut to get the class type using a string

                frcJava(getArtifactTypeClass('FRCJavaArtifact')) {
                    jvmArgs.add("-XX:+UnlockExperimentalVMOptions")
                    jvmArgs.add("-XX:GCTimeRatio=5")
                    jvmArgs.add("-XX:+UseSerialGC")
                    jvmArgs.add("-XX:MaxGCPauseMillis=50")

                    // Enable VisualVM connection
//                    jvmArgs.add("-Dcom.sun.management.jmxremote=true")
//                    jvmArgs.add("-Dcom.sun.management.jmxremote.port=1198")
//                    jvmArgs.add("-Dcom.sun.management.jmxremote.local.only=false")
//                    jvmArgs.add("-Dcom.sun.management.jmxremote.ssl=false")
//                    jvmArgs.add("-Dcom.sun.management.jmxremote.authenticate=false")
//                    jvmArgs.add("-Djava.rmi.server.hostname=10.59.87.2") // Replace TE.AM with team number

                    // The options below may improve performance, but should only be enabled on the RIO 2
                    //
                    final MAX_JAVA_HEAP_SIZE_MB = 100;
                    jvmArgs.add("-Xmx" + MAX_JAVA_HEAP_SIZE_MB + "M")
                    jvmArgs.add("-Xms" + MAX_JAVA_HEAP_SIZE_MB + "M")
                    jvmArgs.add("-XX:+AlwaysPreTouch")
                }

                // Static files artifact
                frcStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) {
                    files = project.fileTree('src/main/deploy')
                    directory = '/home/lvuser/deploy'
                    // Change to true to delete files on roboRIO that no
                    // longer exist in deploy directory on roboRIO
                    deleteOldFiles = false
                }
            }
        }
    }
}

def deployArtifact = deploy.targets.roborio.artifacts.frcJava

// Set to true to use debug for JNI.
wpi.java.debugJni = false

// Set this to true to enable desktop support.
def includeDesktopSupport = true

// Configuration for AdvantageKit
task(replayWatch, type: JavaExec) {
    mainClass = "org.littletonrobotics.junction.ReplayWatch"
    classpath = sourceSets.main.runtimeClasspath
}

// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries.
// Also defines JUnit 4.
dependencies {
    annotationProcessor wpi.java.deps.wpilibAnnotations()
    implementation wpi.java.deps.wpilib()
    implementation wpi.java.vendor.java()

    roborioDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.roborio)
    roborioDebug wpi.java.vendor.jniDebug(wpi.platforms.roborio)

    roborioRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.roborio)
    roborioRelease wpi.java.vendor.jniRelease(wpi.platforms.roborio)

    nativeDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.desktop)
    nativeDebug wpi.java.vendor.jniDebug(wpi.platforms.desktop)
    simulationDebug wpi.sim.enableDebug()

    nativeRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.desktop)
    nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop)
    simulationRelease wpi.sim.enableRelease()

    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"

    implementation 'com.opencsv:opencsv:5.8'

    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0"

    implementation project(':annotation')
    ksp project(':annotation')

    testImplementation platform("org.junit:junit-bom:5.10.1")
    testImplementation "org.junit.jupiter:junit-jupiter-api"
    testImplementation "org.junit.jupiter:junit-jupiter-params"
    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine"
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    def akitJson = new groovy.json.JsonSlurper().parseText(new File(projectDir.getAbsolutePath() + "/vendordeps/AdvantageKit.json").text)
    annotationProcessor "org.littletonrobotics.akit:akit-autolog:$akitJson.version"
}

sourceSets {
    main {
        java {
            srcDirs = [
                    'src/main/java',
                    'src/main/kotlin'
            ]
        }
    }
    test {
        java {
            srcDirs = [
                    'src/test/java',
                    'src/test/kotlin'
            ]
        }
    }
}

test {
    useJUnitPlatform()
    systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
}

// Simulation configuration (e.g. environment variables).
//
// The sim GUI is *disabled* by default to support running
// AdvantageKit log replay from the command line. Set the
// value to "true" to enable the sim GUI by default (this
// is the standard WPILib behavior).
wpi.sim.addGui().defaultEnabled = true
wpi.sim.addDriverstation()

// Setting up my Jar File. In this case, adding all libraries into the main jar ('fat jar')
// in order to make them all available at runtime. Also adding the manifest so WPILib
// knows where to look for our Robot Class.
jar {
    from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
    from sourceSets.main.allSource
    manifest edu.wpi.first.gradlerio.GradleRIOPlugin.javaManifest(ROBOT_MAIN_CLASS)
    duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

// Configure jar and deploy tasks
deployArtifact.jarTask = jar
wpi.java.configureExecutableTasks(jar)
wpi.java.configureTestTasks(test)

// Configure string concat to always inline compile
tasks.withType(JavaCompile) {
    options.compilerArgs.add '-XDstringConcat=inline'
}

// Create version file
project.compileKotlin.dependsOn(createVersionFile)
project.compileJava.dependsOn(createVersionFile)
gversion {
    srcDir       = "src/main/kotlin/"
    classPackage = "frc.robot"
    className    = "BuildConstants"
    dateFormat   = "yyyy-MM-dd HH:mm z"
    timeZone     = "Asia/Jerusalem"
    indent       = "  "
}

tasks.withType(JavaCompile).configureEach {
    // Configure string concat to always inline compile
    options.compilerArgs.add '-XDstringConcat=inline'
}

kotlin {
    compilerOptions {
        jvmTarget.set(JvmTarget.@Companion.fromTarget(javaVersion.toString()))
        // https://kotlinlang.org/docs/gradle-configure-project.html#gradle-java-toolchains-support
        jvmToolchain(Integer.valueOf(javaVersion.toString()))
    }
}

idea {
    project {
        // The project.sourceCompatibility setting is not always picked up, so we set explicitly
        languageLevel = javaVersion
    }
    module {
        // Improve development & (especially) debugging experience (and IDEA's capabilities) by having libraries' source & javadoc attached
        downloadJavadoc = true
        downloadSources = true
        // Exclude the .vscode directory from indexing and search
        excludeDirs += file(".vscode")
    }
}

// Create commit with working changes on event branches
task(eventDeploy) {
    doLast {
        if (project.gradle.startParameter.taskNames.any({ it.toLowerCase().contains("deploy") })) {
            def branchPrefix = "event"
            def branch = 'git branch --show-current'.execute().text.trim()
            def commitMessage = "Update at '${new Date().toString()}'"

            if (branch.startsWith(branchPrefix)) {
                exec {
                    workingDir(projectDir)
                    executable 'git'
                    args 'add', '-A'
                }
                exec {
                    workingDir(projectDir)
                    executable 'git'
                    args 'commit', '-m', commitMessage
                    ignoreExitValue = true
                }

                println "Committed to branch: '$branch'"
                println "Commit message: '$commitMessage'"
            } else {
                println "Not on an event branch, skipping commit"
            }
        } else {
            println "Not running deploy task, skipping commit"
        }
    }
}
createVersionFile.dependsOn(eventDeploy)

//spotless formatting
spotless {
    format 'misc', {
        // define the files to apply `misc` to
        target '*gradle*', '.gitattributes', '.gitignore'

        // define the steps to apply to those files
        trimTrailingWhitespace()
        indentWithSpaces(4)
        endWithNewline()
    }
    java {
        targetExclude('**/BuildConstants.java')

        // use AOSP style for 4-character wide indents
        googleJavaFormat().aosp()

        // fix formatting of type annotations
        trimTrailingWhitespace()
        endWithNewline()
    }
    kotlin {
        targetExclude('build/')

        ktfmt().googleStyle().configure {
            it.setBlockIndent(4)
            it.setContinuationIndent(4)
            it.setMaxWidth(80)
            it.setRemoveUnusedImport(true)
        }
    }
}
