buildscript {
    dependencies {
        classpath 'com.guardsquare:proguard-gradle:7.5.0'
    }
}

plugins {
    id 'net.neoforged.moddev'
    id 'maven-publish'
    id 'com.gradleup.shadow'
    id 'signing'
}

apply plugin: ProjectDefaultsPlugin
apply plugin: FlatBuffersPlugin

evaluationDependsOn ":markdown"

group = "org.appliedenergistics"
base {
    archivesName = "guideme"
}

sourceSets {
    main {
        resources {
            srcDir 'src/generated/resources'
        }
    }
    testmod
}

configurations {
    localImplementation
    shaded {
        transitive = false
    }
    // Dependencies only used for the guide export, but not shipped
    guideExportOnly
    configurations.compileClasspath.extendsFrom(guideExportOnly)
    configurations.runtimeClasspath.extendsFrom(guideExportOnly)

    compileClasspath.extendsFrom localImplementation
    runtimeClasspath.extendsFrom localImplementation
    testCompileClasspath.extendsFrom localImplementation
    testRuntimeClasspath.extendsFrom localImplementation
    testmodRuntimeClasspath.extendsFrom shaded
}

dependencies {
    // To be copied into the jar file
    shaded project(path: ':markdown', configuration: "archives")
    shaded "io.methvin:directory-watcher:${directory_watcher_version}"
    shaded "org.yaml:snakeyaml:${snakeyaml_version}"
    shaded "com.google.flatbuffers:flatbuffers-java:${flatbuffers_version}"

    api(project(':markdown')) {
        transitive = false
    }
    // Do not inherit any transitive dependencies here since we rely on those transitive dependencies being
    // present in Minecrafts own dependencies already.
    localImplementation("io.methvin:directory-watcher:${directory_watcher_version}") {
        transitive = false
    }
    localImplementation("org.yaml:snakeyaml:${snakeyaml_version}") {
        transitive = false
    }
    localImplementation("com.google.flatbuffers:flatbuffers-java:${flatbuffers_version}") {
        transitive = false
    }
    shaded(localImplementation("org.apache.lucene:lucene-core:${lucene_version}"))
    shaded(localImplementation("org.apache.lucene:lucene-analysis-common:${lucene_version}"))
    shaded(localImplementation("org.apache.lucene:lucene-queryparser:${lucene_version}"))
    shaded(localImplementation("org.apache.lucene:lucene-facet:${lucene_version}"))
    shaded(localImplementation("org.apache.lucene:lucene-queries:${lucene_version}"))
    shaded(localImplementation("org.apache.lucene:lucene-highlighter:${lucene_version}"))
    shaded(localImplementation("org.apache.lucene:lucene-memory:${lucene_version}"))

    // Used for the guide export
    guideExportOnly("org.bytedeco:ffmpeg-platform:${ffmpeg_version}")

    // unit test dependencies
    testImplementation(platform("org.junit:junit-bom:${junit_version}"))
    testImplementation(platform("org.assertj:assertj-bom:${assertj_version}"))
    testImplementation("org.junit.jupiter:junit-jupiter-api")
    testImplementation("org.junit.jupiter:junit-jupiter-params")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
    testImplementation("org.junit.platform:junit-platform-launcher")
    testImplementation("org.assertj:assertj-core")
    testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
    testImplementation("net.neoforged:testframework:${neoforge_version}")

    testmodRuntimeOnly sourceSets.main.output
}

///////////////////
// Version Number
ext.tag = System.getenv('TAG') ?: ""
if (ext.tag) {
    if (!ext.tag.startsWith("v")) {
        throw new GradleException("Tags should start with v ${ext.tag}")
    }

    project.version = ext.tag.substring("v".length())
} else {
    // This essentially tries to implement delay expansion of the project version based on a value source to
    // still support configuration caching.
    project.version = providers.gradleProperty("version").orElse("").flatMap(version -> {
        if (!version.isBlank()) {
            return providers.provider { version }
        }
        return providers.of(ProjectVersionSource.class, spec -> {
            spec.getParameters().getDefaultBranches().addAll("main", project.minecraft_version)
        });
    }).get()
}

tasks.register("printProjectVersion", PrintProjectVersion.class);

final testModGuidePath = file('src/testmod/resources/assets/testmod/guides/testmod/guide').absolutePath

test {
    useJUnitPlatform()

    systemProperty 'guideme.testmod.guide.sources', testModGuidePath
}

neoForge {
    enable {
        version = project.neoforge_version
        enabledSourceSets = [sourceSets.main, sourceSets.testmod]
    }

    validateAccessTransformers = true

    mods {
        guideme {
            sourceSet sourceSets.main
        }
        testmod {
            sourceSet sourceSets.testmod
        }
        guidemetest {
            sourceSet sourceSets.main
            sourceSet sourceSets.test
        }
    }

    runs {
        configureEach {
            gameDirectory = project.file('run')

            loadedMods = [mods.guideme, mods.testmod]
            sourceSet = sourceSets.testmod

            systemProperty("guideme.testmod.guide.sources", testModGuidePath)
        }
        client {
            client()
        }
        server {
            server()
        }
        gametestWorld {
            client()
            programArguments = [
                    "--username", "GuideMEDev", "--quickPlaySingleplayer", "GametestWorld"
            ]
        }
        guide {
            client()
            systemProperty('guideme.showOnStartup', 'testmod:guide')
        }
        data {
            clientData()
            programArguments = [
                    '--mod', 'guideme',
                    '--all',
                    '--output', file('src/generated/resources/').absolutePath,
                    '--existing', file('src/main/resources').absolutePath
            ]
        }
        exportTestGuide {
            client()
            systemProperty('guideme.exportOnStartupAndExit', 'testmod:guide')
            systemProperty('guideme.exportDestination.testmod.guide', file('build/exportedGuide').absolutePath)
        }
    }

    unitTest {
        enable()
        testedMod = mods.guidemetest
        loadedMods = [mods.guidemetest, mods.testmod]
    }
}

final generateModMetadata = tasks.register('generateModMetadata', ProcessResources) {
    group = 'build'
    from('src/main/neoforge.mods.toml') {
        rename '(.*)', 'META-INF/$1'
    }
    into 'build/generated/modMetadata'

    // Exposed project properties
    Map<String, String> projectProperties = [
            'version',
            'neoforge_version_range',
            'minecraft_version_range'
    ].collectEntries { [it, project[it]] }

    // Ensure the resources get re-evaluate when the version changes
    inputs.properties projectProperties
    expand projectProperties
}
sourceSets.main.resources.srcDir generateModMetadata
neoForge.ideSyncTask generateModMetadata

jar {
    finalizedBy shadowJar
    archiveClassifier = "plain"
    manifest {
        attributes.put("Implementation-Version", project.version)
    }
}

shadowJar {
    from sourceSets.main.output.classesDirs
    from sourceSets.main.output.resourcesDir

    dependencies {
        exclude 'META-INF/maven/**'
    }
    mergeServiceFiles()

    relocate "io.methvin", "guideme.internal.shaded.methvin"
    relocate "org.yaml.snakeyaml", "guideme.internal.shaded.snakeyaml"
    relocate "com.google.flatbuffers", "guideme.internal.shaded.flatbuffers"
    relocate "org.apache.lucene", "guideme.internal.shaded.lucene"
    relocate "org.tartarus.snowball", "guideme.internal.shaded.snowball"

    configurations = [project.configurations.shaded]
    archiveClassifier = 'all'
}

File proguardFile = file("build/libs/${jar.archiveBaseName.get()}-${version}-proguard.jar")

final proguardConfig = tasks.register('generateProguardConfig', GenerateProGuardConfig) {
    template = file('proguard.conf')
    sourceDir = layout.projectDirectory.dir('src/main/java')
    output = layout.buildDirectory.file('generated/proguard.conf')
}

final proguardJar = tasks.register('proguardJar', proguard.gradle.ProGuardTask) {
    dependsOn shadowJar
    outputs.upToDateWhen { false }

    if (JavaLanguageVersion.current().asInt() <= 8) {
        libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
    } else {
        libraryjars "${System.getProperty('java.home')}/jmods"
    }
    libraryjars(configurations.compileClasspath)

    injars(shadowJar.archiveFile)
    outjars proguardFile
    configuration proguardConfig
}

File postprocessedFile = file("build/libs/${jar.archiveBaseName.get()}-${version}.jar")
final postProcessJar = tasks.register('postProcessJar', PostProcessProGuardFile) {
    input.from(proguardJar.map { it.getOutJarFileCollection() })
    output = postprocessedFile
}
assemble.dependsOn postProcessJar

def publicApiIncludePatterns = {
    exclude "**/*Internal.*"
    exclude "**/*Internal\$*.*"
    exclude "**/internal/**"
}

javadoc {
    source = sourceSets.main.allJava
    classpath = sourceSets.main.compileClasspath + sourceSets.main.output

    options.addStringOption('Xdoclint:none', '-quiet')
    options.encoding = 'UTF-8'
    options.charSet = 'UTF-8'
}
javadoc publicApiIncludePatterns

tasks.register('javadocJar', Jar) {
    dependsOn javadoc
    archiveClassifier = "javadoc"
    from javadoc.destinationDir
}

tasks.register('sourcesJar', Jar) {
    archiveClassifier = "sources"
    from sourceSets.main.allJava
}

tasks.register('apiJar', Jar) {
    archiveClassifier = "api"
    // api jar ist just a development aid and serves as both a binary and source jar simultaneously
    from sourceSets.main.output
    from sourceSets.main.allJava
    from project(":markdown").sourceSets.main.output
    include "**/*.class"
}
apiJar publicApiIncludePatterns

artifacts {
    archives javadocJar
    archives sourcesJar
    archives apiJar
}

//////////////////
// Maven publish
publishing {
    publications {
        maven(MavenPublication) {
            artifactId = "guideme"
            version = project.version
            pom {
                name = "GuideME"
                description = "GuideME offers the foundation for your Minecraft guidebook needs, be it for mods or modpacks."
                url = "https://guideme.appliedenergistics.org"
                scm {
                    connection = "scm:git:git://github.com/AppliedEnergistics/GuideME.git"
                    developerConnection = "scm:git:ssh://github.com:AppliedEnergistics/GuideME.git"
                    url = "https://github.com/AppliedEnergistics/GuideME/tree/main"
                }
                licenses {
                    license {
                        name = "LGPLv3, MIT, and Apache License v2"
                        url = "https://guideme.appliedenergistics.org/license"
                    }
                }
                developers {
                    developer {
                        name = "shartte"
                        email = "team@appliedenergistics.org"
                        organization = "Applied Energistics"
                        organizationUrl = "https://github.com/AppliedEnergistics/"
                    }
                }
            }

            artifact(postprocessedFile) {
                builtBy(postProcessJar)
            }
            artifact sourcesJar
            artifact javadocJar
            artifact apiJar
        }
    }
    repositories {
        maven {
            name = "Local"
            url = file("build/repo").toURI()
        }
    }
}

signing {
    def signingKey = findProperty("signingKey")
    def signingPassword = findProperty("signingPassword")
    required = signingKey != null && signingPassword != null
    useInMemoryPgpKeys(signingKey, signingPassword)
    sign publishing.publications.maven
}

afterEvaluate {
    println('Version: ' + project.version)
}
