plugins {
	id 'java'
	id 'maven-publish'
	id 'java-gradle-plugin'
	id 'idea'
	id 'eclipse'
	id 'groovy'
	id 'checkstyle'
	id 'jacoco'
	id 'codenarc'
	id "org.jetbrains.kotlin.jvm" version "1.5.31" // Must match the version included with gradle.
	id "com.diffplug.spotless" version "6.3.0"
}

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

tasks.withType(JavaCompile).configureEach {
	it.options.encoding = "UTF-8"
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
	kotlinOptions {
		jvmTarget = "16" // Change to 17 when updating gradle/kotlin to 1.6.10
	}
}

group = 'net.fabricmc'
archivesBaseName = project.name
def baseVersion = '0.13'

def ENV = System.getenv()
if (ENV.BUILD_NUMBER) {
	version = baseVersion + '.' + ENV.BUILD_NUMBER
} else {
	version = baseVersion + '.local'
}

repositories {
	maven {
		name = 'Fabric'
		url = 'https://maven.fabricmc.net/'
	}
	mavenCentral()
}

configurations {
	bootstrap {
		transitive false
	}
	compileClasspath.extendsFrom bootstrap
	runtimeClasspath.extendsFrom bootstrap
	testRuntimeClasspath.extendsFrom bootstrap
}

configurations.all {
	resolutionStrategy {
		failOnNonReproducibleResolution()
	}
}

dependencies {
	implementation gradleApi()

	bootstrap project(":bootstrap")

	// libraries
	implementation ('commons-io:commons-io:2.11.0')
	implementation ('com.google.code.gson:gson:2.9.0')
	implementation ('com.fasterxml.jackson.core:jackson-databind:2.13.3')
	implementation ('com.google.guava:guava:31.1-jre')
	implementation ('org.ow2.asm:asm:9.3')
	implementation ('org.ow2.asm:asm-analysis:9.3')
	implementation ('org.ow2.asm:asm-commons:9.3')
	implementation ('org.ow2.asm:asm-tree:9.3')
	implementation ('org.ow2.asm:asm-util:9.3')

	// game handling utils
	implementation ('net.fabricmc:stitch:0.6.1') {
		exclude module: 'enigma'
	}

	// tinyfile management
	implementation ('net.fabricmc:tiny-remapper:0.8.5')
	implementation 'net.fabricmc:access-widener:2.1.0'
	implementation 'net.fabricmc:mapping-io:0.2.1'

	implementation ('net.fabricmc:lorenz-tiny:4.0.2') {
		transitive = false
	}

	// decompilers
	implementation ('net.fabricmc:fabric-fernflower:1.5.0')
	implementation ('net.fabricmc:cfr:0.1.1')

	// source code remapping
	implementation ('net.fabricmc:mercury:0.2.6')

	// Kotlin
	implementation('org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.4.2') {
		transitive = false
	}

	// Kapt integration
	compileOnly('org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31') // Must match the version included with gradle.

	// Testing
	testImplementation(gradleTestKit())
	testImplementation('org.spockframework:spock-core:2.1-groovy-3.0') {
		exclude module: 'groovy-all'
	}
	testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
	testImplementation ('io.javalin:javalin:4.6.1') {
		exclude group: 'org.jetbrains.kotlin'
	}
	testImplementation 'net.fabricmc:fabric-installer:0.9.0'
	testImplementation 'org.mockito:mockito-core:4.6.1'

	compileOnly 'org.jetbrains:annotations:23.0.0'
	testCompileOnly 'org.jetbrains:annotations:23.0.0'
}

jar {
	manifest {
		attributes 'Implementation-Version': project.version
	}

	from configurations.bootstrap.collect { it.isDirectory() ? it : zipTree(it) }
}

java {
	withSourcesJar()
}

spotless {
	java {
		licenseHeaderFile(rootProject.file("HEADER")).yearSeparator("-")
		targetExclude("**/loom/util/DownloadUtil.java")
	}

	groovy {
		licenseHeaderFile(rootProject.file("HEADER")).yearSeparator("-")
	}

	kotlin {
		licenseHeaderFile(rootProject.file("HEADER")).yearSeparator("-")
		targetExclude("**/build.gradle.kts")
		targetExclude("src/test/resources/projects/*/**")
		ktlint()
	}
}

checkstyle {
	configFile = file('checkstyle.xml')
	toolVersion = '9.3'
}

codenarc {
	toolVersion = "2.2.0"
	configFile = file("codenarc.groovy")
}

gradlePlugin {
	plugins {
		fabricLoom {
			id = 'fabric-loom'
			implementationClass = 'net.fabricmc.loom.bootstrap.LoomGradlePluginBootstrap'
		}
	}
}

jacoco {
	toolVersion = "0.8.7"
}

// Run to get test coverage.
jacocoTestReport {
	dependsOn test
	reports {
		xml.required = false
		csv.required = false
		html.destination file("${buildDir}/jacocoHtml")
	}
}

test {
	maxHeapSize = "1536m"
	useJUnitPlatform()

	// Forward system prop onto tests.
	if (System.getProperty("fabric.loom.test.homeDir")) {
		systemProperty "fabric.loom.test.homeDir", System.getProperty("fabric.loom.test.homeDir")
	}
}

import org.gradle.util.GradleVersion
import org.w3c.dom.Document
import org.w3c.dom.Element
import org.w3c.dom.Node

publishing {
	publications {
		plugin(MavenPublication) { publication ->
			groupId project.group
			artifactId project.archivesBaseName
			version project.version

			from components.java
		}

		// Also publish a snapshot so people can use the latest version if they wish
		snapshot(MavenPublication) { publication ->
			groupId project.group
			artifactId project.archivesBaseName
			version baseVersion + '-SNAPSHOT'

			from components.java
		}

		// Manually crate the plugin marker for snapshot versions
		snapshotPlugin(MavenPublication) { publication ->
			groupId 'fabric-loom'
			artifactId 'fabric-loom.gradle.plugin'
			version baseVersion + '-SNAPSHOT'

			pom.withXml({
				// Based off org.gradle.plugin.devel.plugins.MavenPluginPublishPlugin
				Element root = asElement()
				Document document = root.getOwnerDocument()
				Node dependencies = root.appendChild(document.createElement('dependencies'))
				Node dependency = dependencies.appendChild(document.createElement('dependency'))
				Node groupId = dependency.appendChild(document.createElement('groupId'))
				groupId.setTextContent('net.fabricmc')
				Node artifactId = dependency.appendChild(document.createElement('artifactId'))
				artifactId.setTextContent('fabric-loom')
				Node version = dependency.appendChild(document.createElement('version'))
				version.setTextContent(baseVersion + '-SNAPSHOT')
			})
		}
	}
	repositories {
		maven {
			if (ENV.MAVEN_URL) {
				url ENV.MAVEN_URL
				credentials {
					username ENV.MAVEN_USERNAME
					password ENV.MAVEN_PASSWORD
				}
			}
		}
	}
}

// Need to tweak this file to pretend we are compatible with j8 so the bootstrap will run.
tasks.withType(GenerateModuleMetadata) {
	doLast {
		def file = outputFile.get().asFile

		def metadata = new groovy.json.JsonSlurper().parseText(file.text)

		metadata.variants.each {
			it.attributes["org.gradle.jvm.version"] = 8
		}

		file.text = groovy.json.JsonOutput.toJson(metadata)
	}
}

// A task to output a json file with a list of all the test to run
task writeActionsTestMatrix() {
	doLast {
		def testMatrix = []
		file('src/test/groovy/net/fabricmc/loom/test/integration').eachFile {
			if (it.name.endsWith("Test.groovy")) {
				if (it.name.endsWith("ReproducibleBuildTest.groovy")) {
					// This test gets a special case to run across all os's
					return
				}

				def className = it.name.replace(".groovy", "")

				// Disabled for CI, as it fails too much.
				if (className.endsWith("DecompileTest")) return

				testMatrix.add("net.fabricmc.loom.test.integration.${className}")
			}
		}

		// Run all the unit tests together
		testMatrix.add("net.fabricmc.loom.test.unit.*")

		// Kotlin tests
		testMatrix.add("net.fabricmc.loom.test.kotlin.*")

		def json = groovy.json.JsonOutput.toJson(testMatrix)
		def output = file("build/test_matrix.json")
		output.parentFile.mkdir()
		output.text = json
	}
}

tasks.named('wrapper') {
	distributionType = Wrapper.DistributionType.ALL
}

/**
 * Run this task to download the gradle sources next to the api jar, you may need to manually attach the sources jar
 */
task downloadGradleSources() {
	doLast {
		// Awful hack to find the gradle api location
		def gradleApiFile = project.configurations.detachedConfiguration(dependencies.gradleApi()).files.stream()
			.filter {
				it.name.startsWith("gradle-api")
			}.findFirst().orElseThrow()

		def gradleApiSources = new File(gradleApiFile.absolutePath.replace(".jar", "-sources.jar"))
		def url = "https://services.gradle.org/distributions/gradle-${GradleVersion.current().getVersion()}-src.zip"

		gradleApiSources.delete()

		println("Downloading (${url}) to (${gradleApiSources})")
		gradleApiSources << new URL(url).newInputStream()
	}
}