buildscript {
	dependencies {
		classpath 'org.kohsuke:github-api:1.135'
	}
}

plugins {
	id "java-library"
	id "eclipse"
	id "idea"
	id "maven-publish"
	id "fabric-loom" version "0.11.32" apply false
	id "org.cadixdev.licenser" version "0.6.1"
	id "org.ajoberstar.grgit" version "3.1.0"
	id "com.matthewprenger.cursegradle" version "1.4.0"
	id "com.modrinth.minotaur" version "1.1.0"
	id "me.modmuss50.remotesign" version "0.2.4" apply false
}

def ENV = System.getenv()
def signingEnabled = ENV.SIGNING_SERVER

version = project.version + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()
logger.lifecycle("Building Fabric: " + version)

import org.apache.commons.codec.digest.DigestUtils

def getSubprojectVersion(project) {
	// Get the version from the gradle.properties file
	def version = project.properties["${project.name}-version"]

	if (!version) {
		throw new NullPointerException("Could not find version for " + project.name)
	}

	if (grgit == null) {
		return version + "+nogit"
	}

	def latestCommits = grgit.log(paths: [project.name], maxCommits: 1)

	if (latestCommits.isEmpty()) {
		return version + "+uncommited"
	}

	return version + "+" + latestCommits.get(0).id.substring(0, 8) + DigestUtils.sha256Hex(project.rootProject.minecraft_version).substring(0, 2)
}

def getBranch() {
	def ENV = System.getenv()
	if (ENV.GITHUB_REF) {
		def branch = ENV.GITHUB_REF
		return branch.substring(branch.lastIndexOf("/") + 1)
	}

	if (grgit == null) {
		return "unknown"
	}

	def branch = grgit.branch.current().name
	return branch.substring(branch.lastIndexOf("/") + 1)
}

def moduleDependencies(project, List<String> depNames) {
	def deps = depNames.iterator().collect { project.dependencies.project(path: ":$it", configuration: 'namedElements') }
	project.dependencies {
		deps.each {
			api it
		}
	}

	// As we manually handle the maven artifacts, we need to also manually specify the deps.
	project.publishing {
		publications {
			mavenJava(MavenPublication) {
				pom.withXml {
					def depsNode = asNode().appendNode("dependencies")
					deps.each {
						def depNode = depsNode.appendNode("dependency")
						depNode.appendNode("groupId", it.group)
						depNode.appendNode("artifactId", it.name)
						depNode.appendNode("version", it.version)
						depNode.appendNode("scope", "compile")
					}
				}
			}
		}
	}
}

allprojects {
	apply plugin: "java-library"
	apply plugin: "checkstyle"
	apply plugin: "maven-publish"
	apply plugin: "fabric-loom"
	apply plugin: "org.cadixdev.licenser"
	apply plugin: "me.modmuss50.remotesign"

	tasks.withType(JavaCompile).configureEach {
		it.options.release = 17
	}

	group = "net.fabricmc.fabric-api"

	sourceSets {
		testmod {
			compileClasspath += main.compileClasspath
			runtimeClasspath += main.runtimeClasspath
		}
	}

	loom {
		runtimeOnlyLog4j = true

		runs {
			testmodClient {
				client()
				ideConfigGenerated project.rootProject == project
				name = "Testmod Client"
				source sourceSets.testmod
			}
			testmodServer {
				server()
				ideConfigGenerated project.rootProject == project
				name = "Testmod Server"
				source sourceSets.testmod
			}
		}
	}

	dependencies {
		minecraft "com.mojang:minecraft:$rootProject.minecraft_version"
		mappings "net.fabricmc:yarn:${rootProject.minecraft_version}${project.yarn_version}:v2"
		modApi "net.fabricmc:fabric-loader:${project.loader_version}"
	}

	loom {
		shareRemapCaches = true
	}

	repositories {
		mavenLocal()
	}

	processResources {
		inputs.property "version", project.version

		filesMatching("fabric.mod.json") {
			expand "version": project.version
		}
	}

	license {
		header rootProject.file("HEADER")
		include "**/*.java"
	}

	java {
		withSourcesJar()
	}

	checkstyle {
		configFile = rootProject.file("checkstyle.xml")
		toolVersion = "9.1"
	}

	tasks.withType(AbstractArchiveTask) {
		preserveFileTimestamps = false
		reproducibleFileOrder = true
	}

	tasks.withType(GenerateModuleMetadata) {
		enabled = false
	}

	if (signingEnabled) {
		remoteSign {
			requestUrl = ENV.SIGNING_SERVER
			pgpAuthKey = ENV.SIGNING_PGP_KEY
			jarAuthKey = ENV.SIGNING_JAR_KEY

			sign remapJar

			afterEvaluate {
				// PGP sign all maven publications.
				sign publishing.publications.mavenJava
			}
		}
	}

	// Run this task after updating minecraft to regenerate any required resources
	task generateResources {
		group = "fabric"
	}
}

// Apply auxiliary buildscripts to submodules
// This must be done after all plugins are applied to subprojects
apply from: "gradle/module-validation.gradle"
apply from: "gradle/module-versioning.gradle"

javadoc {
	options {
		source = "17"
		encoding = "UTF-8"
		charSet = "UTF-8"
		memberLevel = JavadocMemberLevel.PACKAGE
		links(
				"https://guava.dev/releases/21.0/api/docs/",
				"https://asm.ow2.io/javadoc/",
				"https://docs.oracle.com/javase/8/docs/api/",
				"http://jenkins.liteloader.com/job/Mixin/javadoc/",
				"https://logging.apache.org/log4j/2.x/log4j-api/apidocs/"
				// Need to add minecraft jd publication etc once there is one available
		)
		// Disable the crazy super-strict doclint tool in Java 8
		addStringOption("Xdoclint:none", "-quiet")
	}

	allprojects.each {
		source(it.sourceSets.main.allJava.srcDirs)
	}

	classpath = sourceSets.main.compileClasspath
	include("**/api/**")
	failOnError false
}

task javadocJar(type: Jar) {
	dependsOn javadoc
	from javadoc.destinationDir
	//Set as `fatjavadoc` to prevent an ide form trying to use this javadoc, over using the modules javadoc
	archiveClassifier = "fatjavadoc"
}

build.dependsOn javadocJar

loom {
	runs {
		gametest {
			inherit testmodServer

			name "Game Test"

			// Enable the gametest runner
			vmArg "-Dfabric-api.gametest"
			vmArg "-Dfabric-api.gametest.report-file=${project.buildDir}/junit.xml"
			runDir "build/gametest"
		}
		autoTestServer {
			inherit testmodServer

			name "Auto Test Server"

			vmArg "-Dfabric.autoTest"
		}
	}
}
test.dependsOn runGametest

subprojects {
	dependencies {
		testmodImplementation sourceSets.main.output

		// Make all modules depend on the gametest api (and thus res loader) to try and promote its usage.
		if (project.name != "fabric-gametest-api-v1") {
			testmodImplementation project(path: ':fabric-gametest-api-v1', configuration: 'namedElements')
			testmodImplementation project(path: ':fabric-resource-loader-v0', configuration: 'namedElements')
		}

		// Make all testmods run with registry-sync-v0 as it is required to register new objects.
		if (project.name != "fabric-registry-sync-v0") {
			testmodRuntimeOnly project(path: ':fabric-registry-sync-v0', configuration: 'namedElements')
		}
	}

	publishing {
		publications {
			mavenJava(MavenPublication) {
				artifact(signingEnabled ? signRemapJar.output : remapJar) {
					builtBy(signingEnabled ? signRemapJar : remapJar)
				}

				artifact(remapSourcesJar) {
					builtBy remapSourcesJar
				}
			}
		}

		setupRepositories(repositories)
	}

	// We manually handle the pom generation
	loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava)

	javadoc.enabled = false

	afterEvaluate {
		// Disable the gen sources task on sub projects
		genSourcesWithFernFlower.enabled = false
		genSourcesWithCfr.enabled = false
		unpickJar.enabled = false
	}
}

task remapMavenJar(type: net.fabricmc.loom.task.RemapJarTask, dependsOn: jar) {
	input = jar.archiveFile
	archiveFileName = "${archivesBaseName}-${project.version}-maven.jar"
	addNestedDependencies = false
}
build.dependsOn remapMavenJar

if (signingEnabled) {
	remoteSign {
		sign remapMavenJar
	}
}

publishing {
	publications {
		mavenJava(MavenPublication) {
			artifact(signingEnabled ? signRemapMavenJar.output : remapMavenJar) {
				builtBy(signingEnabled ? signRemapMavenJar : remapMavenJar)
			}

			artifact(sourcesJar) {
				builtBy remapSourcesJar
			}

			artifact javadocJar

			pom.withXml {
				def depsNode = asNode().appendNode("dependencies")
				subprojects.each {
					def depNode = depsNode.appendNode("dependency")
					depNode.appendNode("groupId", it.group)
					depNode.appendNode("artifactId", it.name)
					depNode.appendNode("version", it.version)
					depNode.appendNode("scope", "compile")
				}
			}
		}
	}

	setupRepositories(repositories)
}

// Required until the deprecation is removed. Fabric API's main jar that is published to maven does not contain sub modules.
loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava)

void setupRepositories(RepositoryHandler repositories) {
	//repositories.mavenLocal() // uncomment for testing
	def ENV = System.getenv()
	if (ENV.MAVEN_URL) {
		repositories.maven {
			url ENV.MAVEN_URL
			if (ENV.MAVEN_USERNAME) {
				credentials {
					username ENV.MAVEN_USERNAME
					password ENV.MAVEN_PASSWORD
				}
			}
		}
	}
}

task licenseFormatAll
subprojects { p -> licenseFormatAll.dependsOn("${p.path}:licenseFormat") }
subprojects.each { remapJar.dependsOn("${it.path}:remapJar") }

sourceSets {
	testmod
}

// These modules are not included in the fat jar, maven will resolve them via the pom.
def devOnlyModules = [
		"fabric-gametest-api-v1",
		"fabric-data-generation-api-v1"
]

dependencies {
	afterEvaluate {
		subprojects.each {
			api project(path: ":${it.name}", configuration: "namedElements")

			testmodImplementation project("${it.name}:").sourceSets.testmod.output
		}
	}
}

remapJar {
	afterEvaluate {
		subprojects.each {
			if (it.name in devOnlyModules) return

			// Include the signed or none signed jar from the sub project.
			nestedJars.from project("${it.name}:").tasks.getByName(signingEnabled ? "signRemapJar" : "remapJar")
		}
	}
}

curseforge {
	if (ENV.CURSEFORGE_API_KEY) {
		apiKey = ENV.CURSEFORGE_API_KEY
	}

	project {
		id = "306612"
		changelog = ENV.CHANGELOG ?: "No changelog provided"
		releaseType = project.prerelease == "true" ? "beta" : "release"
		addGameVersion "1.18.2"
		addGameVersion "Fabric"

		mainArtifact(signingEnabled ? signRemapJar.output : remapJar) {
			displayName = "[$project.minecraft_version] Fabric API $project.version"
		}

		afterEvaluate {
			uploadTask.dependsOn("remapJar")
		}
	}

	options {
		forgeGradleIntegration = false
	}
}

if (signingEnabled) {
	project.tasks.curseforge.dependsOn signRemapJar
	build.dependsOn signRemapJar
}

import org.kohsuke.github.GHReleaseBuilder
import org.kohsuke.github.GitHub

task github(dependsOn: (signingEnabled ? signRemapJar : remapJar)) {
	onlyIf {
		ENV.GITHUB_TOKEN
	}

	doLast {
		def github = GitHub.connectUsingOAuth(ENV.GITHUB_TOKEN as String)
		def repository = github.getRepository(ENV.GITHUB_REPOSITORY)

		def releaseBuilder = new GHReleaseBuilder(repository, version as String)
		releaseBuilder.name("[$project.minecraft_version] Fabric API $project.version")
		releaseBuilder.body(ENV.CHANGELOG ?: "No changelog provided")
		releaseBuilder.commitish(getBranch())
		releaseBuilder.prerelease(project.prerelease == "true")

		def ghRelease = releaseBuilder.create()
		ghRelease.uploadAsset(signingEnabled ? signRemapJar.output.get().getAsFile() : remapJar.archiveFile.get().getAsFile(), "application/java-archive");
	}
}

task modrinth(type: com.modrinth.minotaur.TaskModrinthUpload, dependsOn: (signingEnabled ? signRemapJar : remapJar)) {
	onlyIf {
		ENV.MODRINTH_TOKEN
	}

	token = ENV.MODRINTH_TOKEN
	projectId = "P7dR8mSH"
	versionNumber = version
	versionName = "[$project.minecraft_version] Fabric API $project.version"
	releaseType = project.prerelease == "true" ? "beta" : "release"
	changelog = ENV.CHANGELOG ?: "No changelog provided"

	uploadFile = signingEnabled ? signRemapJar.output : remapJar

	addGameVersion(project.minecraft_version)
	addLoader('fabric')
}

// A task to ensure that the version being released has not already been released.
task checkVersion {
	doFirst {
		def xml = new URL("https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/maven-metadata.xml").text
		def metadata = new XmlSlurper().parseText(xml)
		def versions = metadata.versioning.versions.version*.text();
		if (versions.contains(version)) {
			throw new RuntimeException("${version} has already been released!")
		}
	}
}

github.mustRunAfter checkVersion
modrinth.mustRunAfter checkVersion
publish.mustRunAfter checkVersion
project.tasks.curseforge.mustRunAfter checkVersion