package moe.nea.firmament.annotations.process

import com.google.auto.service.AutoService
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSName

class CompatMetaProcessor(val logger: KSPLogger, val codeGenerator: CodeGenerator, val sourceSetName: String) :
	SymbolProcessor {
	override fun process(resolver: Resolver): List<KSAnnotated> {
		val files = resolver.getAllFiles().toList()
		val packages = files.mapTo(mutableSetOf()) { it.packageName.asString() }
		packages.add("moe.nea.firmament.annotations.generated.$sourceSetName")
		val compatMeta = resolver.getSymbolsWithAnnotation("moe.nea.firmament.util.compatloader.CompatMeta")
			.singleOrNull() as KSClassDeclaration? ?: return listOf()
		val dependencies = Dependencies(aggregating = true, *files.toTypedArray())
		val generatedFileName = "GeneratedCompat${sourceSetName.replaceFirstChar { it.uppercaseChar() }}"
		val compatFile =
			codeGenerator.createNewFile(dependencies, "moe.nea.firmament.annotations.generated.$sourceSetName", generatedFileName)
				.bufferedWriter()
		compatFile.appendLine("// This file is @generated by SubscribeAnnotationProcessor")
		compatFile.appendLine("// Do not edit")
		compatFile.appendLine("package moe.nea.firmament.annotations.generated.$sourceSetName")
		compatFile.appendLine("class $generatedFileName : moe.nea.firmament.util.compatloader.ICompatMetaGen {")
		compatFile.appendLine("""
	override fun owns(className: String): Boolean {
		return moe.nea.firmament.util.compatloader.CompatHelper.isOwnedByPackage(className, ${
			packages.joinToString { "\"" + it + "\"" }
		})
	}

	override val meta: moe.nea.firmament.util.compatloader.ICompatMeta
		get() = ${compatMeta.qualifiedName!!.asString()}
""")
		compatFile.appendLine("}")
		compatFile.close()
		val metaInf = codeGenerator.createNewFileByPath(
			dependencies,
			"META-INF/services/moe.nea.firmament.util.compatloader.ICompatMetaGen", extensionName = "")
			.bufferedWriter()
		metaInf.append("moe.nea.firmament.annotations.generated.$sourceSetName.")
		metaInf.appendLine(generatedFileName)
		metaInf.close()
		return listOf()
	}


	@AutoService(SymbolProcessorProvider::class)
	class Provider : SymbolProcessorProvider {
		override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
			return CompatMetaProcessor(environment.logger,
			                           environment.codeGenerator,
			                           environment.options["firmament.sourceset"] ?: "main")
		}
	}
}
