import groovy.json.JsonSlurper

/*
 * This buildscript contains tasks related to the validation of each module in fabric api.
 *
 * Right now this task verifies each Fabric API module has a module lifecycle specified.
 * More functionality will probably be added in the future.
 */

subprojects {
	if (it.name == "deprecated" || it.name == "fabric-api-bom" || it.name == "fabric-api-catalog") {
		return
	}

	// Create the task
	def validateModules = tasks.register("validateModules", ValidateModuleTask)
	tasks.check.dependsOn(validateModules)
}

/**
 * Verifies that each module has the required custom values for module lifecycle in it's FMJ.
 *
 * <p>Example:
 * <pre>{@code
 * "custom": {
 *   "fabric-api:module-lifecycle": "stable"
 * }
 * }</pre>
 */
abstract class ValidateModuleTask extends DefaultTask {
	@InputFile
	abstract RegularFileProperty getFmj()

	@Input
	abstract Property<String> getProjectName()

	@Input
	abstract Property<String> getProjectPath()

	@Input
	abstract Property<String> getLoaderVersion()

	ValidateModuleTask() {
		group = "verification"

		// No outputs
		outputs.upToDateWhen { true }

		def file = project.file("src/main/resources/fabric.mod.json")

		if (!file.exists()) {
			file = project.file("src/client/resources/fabric.mod.json")
		}

		fmj.set(file)

		projectName.set(project.name)
		projectPath.set(project.path)
		loaderVersion.set(project.loader_version)
	}

	@TaskAction
	void validate() {
		def file = fmj.get().asFile

		def json = new JsonSlurper().parse(file)

		if (json.custom == null) {
			throw new GradleException("Module ${projectName.get()} does not have a custom value containing module lifecycle!")
		}

		def moduleLifecycle = json.custom.get("fabric-api:module-lifecycle")

		if (moduleLifecycle == null) {
			throw new GradleException("Module ${projectName.get()} does not have module lifecycle in custom values!")
		}

		if (!moduleLifecycle instanceof String) {
			throw new GradleException("Module ${projectName.get()} has an invalid module lifecycle value. The value must be a string but read a ${moduleLifecycle.class}")
		}

		// Validate the lifecycle value
		switch (moduleLifecycle) {
			case "stable":
			case "experimental":
				break
			case "deprecated":
				if (!projectPath.get().startsWith(":deprecated")) {
					throw new GradleException("Deprecated module ${projectName.get()} must be in the deprecated sub directory.")
				}
				break
			default:
				throw new GradleException("Module ${projectName.get()} has an invalid module lifecycle ${json.custom.get('fabric-api:module-lifecycle')}")
		}

		if (json.depends == null) {
			throw new GradleException("Module ${projectName.get()} does not have a depends value!")
		}

		if (json.depends.fabricloader != ">=${loaderVersion.get()}") {
			throw new GradleException("Module ${projectName.get()} does not have a valid fabricloader value! Got \"${json.depends.fabricloader}\" but expected \">=${project.loader_version}\"")
		}
	}
}
