import io.franzbecker.gradle.lombok.task.DelombokTask

plugins {
    id 'com.gradleup.shadow' version '8.3.6'
    id 'io.franzbecker.gradle-lombok' version '5.0.0'
}

repositories {
    mavenCentral()
}

allprojects {
    apply plugin: 'java'
    apply plugin: 'jacoco'
    apply plugin: 'java-library'
    apply plugin: 'maven-publish'
    apply plugin: 'com.gradleup.shadow'

    // no lombok for that project, cause its doing naughty things with stubing java.lang classes
    if (project != project(':headlessmc-modlauncher')) {
        // Consider switching to https://github.com/freefair/gradle-plugins/tree/main/lombok-plugin looks more maintained?
        apply plugin: 'io.franzbecker.gradle-lombok'
        lombok {
            version '1.18.34'
        }
    }

    group 'io.github.headlesshq.headlessmc'
    version rootProject.project_version


    repositories {
        mavenCentral()
        maven {
            name '3arthMaven'
            url 'https://3arthqu4ke.github.io/maven'
        }

        maven {
            name 'JitPackMaven'
            url 'https://jitpack.io'
        }
    }

    if (hmc_graal_build.toBoolean()) {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    } else {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8

        compileJava {
            if (JavaVersion.current().isJava9Compatible()) {
                options.compilerArgs.addAll(['--release', '8'])
            }
        }
    }

    configurations {
        jarLibs
        implementation.extendsFrom jarLibs
        jarLibsApi
        api.extendsFrom jarLibsApi
    }

    dependencies {
        compileOnly 'org.jetbrains:annotations:24.1.0'
        testCompileOnly 'org.jetbrains:annotations:24.1.0'

        // no lombok for modlauncher cause we do bad hacks there in the java9 stub.
        if (project != project(':headlessmc-modlauncher')) {
            compileOnly 'org.projectlombok:lombok:1.18.34'
            annotationProcessor 'org.projectlombok:lombok:1.18.34'

            testCompileOnly 'org.projectlombok:lombok:1.18.34'
            testAnnotationProcessor 'org.projectlombok:lombok:1.18.34'
        }

        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.0'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.0'
    }

    test {
        useJUnitPlatform()
        testLogging {
            events "failed"
            exceptionFormat "full"
        }

        finalizedBy jacocoTestReport
    }

    jacocoTestReport {
        dependsOn test
    }

    jar {
        archivesBaseName = project.name
        duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    }

    java {
        withSourcesJar()
        withJavadocJar()
    }

    // TODO: even though we are doing all of this Intellij
    //  still complains about bytecode not matching the source...
    if (sourceSets.main.java.srcDirs.stream().anyMatch { it.exists()}
            && project != project(':headlessmc-modlauncher')
            && (!hmc_graal_build.toBoolean() || project != project(':headlessmc-graalvm'))) {
        tasks.register('delombok', DelombokTask) {
            dependsOn compileJava
            ext.outputDir = file(layout.buildDirectory.dir('delombok'))
            outputs.dir(ext.outputDir)
            sourceSets.main.java.srcDirs.each {
                if (it.exists()) {
                    inputs.dir(it)
                    args(it, '-f', 'suppressWarnings:skip',
                            '-f', 'generated:skip',
                            '-f', 'danceAroundIdeChecks:skip',
                            '-f', 'generateDelombokComment:skip',
                            '-f', 'javaLangAsFQN:skip',
                            '-d', ext.outputDir)
                }
            }
        }

        javadoc {
            dependsOn delombok
            source = delombok.outputDir
        }

        sourcesJar {
            dependsOn delombok
            from delombok.outputDir
            // I tried every single exclude/include pattern but I could not get any to work
            exclude (fileTreeElement -> {
                return !((FileTreeElement) fileTreeElement)
                        .getFile()
                        .toPath()
                        .toAbsolutePath()
                        .startsWith(delombok.outputDir.toPath().toAbsolutePath())
            })
        }

        javadoc {
            options.addStringOption('Xdoclint:none', '-quiet')
            options.linkSource true
        }
    }

    jar {
        archiveClassifier.set('dev')
        manifest {
            attributes(
                "Implementation-Title": project.name,
                "Implementation-Version": version,
            )
        }

        if (project != project(':headlessmc-lwjgl')) {
            manifest {
                attributes(
                    "Automatic-Module-Name": "io.github.headlesshq.${project.name.replace("launcher-", "").replace('-', '.')}"
                )
            }
        }
    }

    shadowJar {
        configurations = [project.configurations.jarLibs, project.configurations.jarLibsApi]
        archiveClassifier.set('')
    }

    jar.finalizedBy(shadowJar)
    def pubSuffix = System.getenv('IS_MAVEN_PUB') != null
            ? ''
            : System.getenv('GITHUB_RUN_NUMBER') != null && System.getenv('GITHUB_SHA') != null
                ? "-${System.getenv('GITHUB_RUN_NUMBER')}-${System.getenv('GITHUB_SHA').substring(0, 7)}"
                : project.version.endsWith('-SNAPSHOT')
                    ? ''
                    : ''

    publishing {
        publications {
            "${project.name.toLowerCase(Locale.ENGLISH)}"(MavenPublication) {
                ((MavenPublication) it).groupId "${project.group}"
                ((MavenPublication) it).artifactId "${project.archivesBaseName.toLowerCase(Locale.ENGLISH)}"
                ((MavenPublication) it).version "${project.version}${pubSuffix}"
                // TODO: testFixtures are part of commons artifact?
                // Exclude shadowJars from publication
                components.withType(AdhocComponentWithVariants).forEach { c ->
                    c.withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
                        skip()
                    }
                }

                from components.java
            }
        }

        repositories {
            // mavenLocal()
            if (System.getenv('DEPLOY_TO_GITHUB_PACKAGES_URL') != null) {
                maven {
                    name = 'GithubPagesMaven'
                    url = System.getenv('DEPLOY_TO_GITHUB_PACKAGES_URL')
                    credentials {
                        username = System.getenv('GITHUB_USER')
                        password = System.getenv('GITHUB_TOKEN')
                    }
                }
            } else {
                maven {
                    name = 'BuildDirMaven'
                    url = rootProject.layout.buildDirectory.dir('maven')
                }
            }
        }
    }

    publish {
        dependsOn(build)
    }

    tasks.withType(Test).tap {
        configureEach {
            jacoco {
                // our classloader potentially includes no ProtectionDomains?
                includeNoLocationClasses true
                jacoco.excludes = ['jdk.internal.*', 'io.github.headlesshq.headlessmc.lwjgl.agent.*']
            }
        }
    }
}

javadoc {
    source subprojects.collect { it.sourceSets.main.allJava }
    classpath = files(subprojects.collect { it.sourceSets.main.compileClasspath })
}

dependencies {
    // create maven publication that contains all modules
    api project(':headlessmc-api')
    api project(':headlessmc-auth')
    api project(':headlessmc-jline')
    api project(':headlessmc-logging')
    api project(':headlessmc-launcher')
    api project(':headlessmc-launcher-wrapper')
    api project(':headlessmc-modlauncher')
    api project(':headlessmc-lwjgl')
    api project(':headlessmc-runtime')
}

tasks.register('jacocoRootReport', JacocoReport) {
    description = 'Generates an aggregate report from all subprojects'
    group = 'verification'
    dependsOn(subprojects.test)

    additionalSourceDirs.from = files(subprojects.sourceSets.main.allSource.srcDirs)
    sourceDirectories.from = files(subprojects.sourceSets.main.allSource.srcDirs)
    classDirectories.from = files(subprojects.sourceSets.main.output)
    executionData.from = files(subprojects.jacocoTestReport.executionData)

    reports {
        xml.required.set(true)
    }
}

tasks.register('copyJars', Copy) {
    dependsOn subprojects.shadowJar
    subprojects.each { subproject ->
        // jfx jar is > 100MB, I do not want to fill my github storage?
        if (subproject.name != 'headlessmc-launcher-jfx') {
            from(subproject.shadowJar)
        }
    }

    into project.file(System.getProperty('hmc.jar.dir', 'build/libs'))
}

build {
    dependsOn(subprojects.shadowJar)
    finalizedBy(copyJars)
}

// the launchers report will otherwise contain coverage data about some of the
// libraries we use in those two jars, e.g. xdarks Deencapsulation
//noinspection ConfigurationAvoidance (idk does not seem to work with it)
tasks.withType(JacocoReport) {
    afterEvaluate {
        classDirectories.setFrom(files(classDirectories.files.collect {
            def tree = fileTree(dir: it, exclude: [
                    '**/headlessmc/headlessmc-launcher.jar',
                    '**/headlessmc-launcher-wrapper.jar',
                    '**/headlessmc/headlessmc-runtime.jar',
                    '**/headlessmc/headlessmc-lwjgl.jar',
                    '**/headlessmc/forge-cli.jar',
                    '**/org/objectweb/asm/**',
                    'io/github/headlesshq/headlessmc/lwjgl/agent/**',
                    'io/github/headlesshq/headlessmc/web/**',
                    'io/github/headlesshq/headlessmc/web/**/*.*',
                    'io/github/headlesshq/headlessmc/web/cheerpj/**/*.*',
                    'io/github/headlesshq/headlessmc/web/cheerpj/plugin/**',
                    'io/github/headlesshq/headlessmc/web/cheerpj/plugin/*.*'
            ])
            // because 'io/github/headlesshq/headlessmc/web/cheerpj/plugin/**' does not work
            return tree.exclude { details ->
                return details.file.canonicalPath.contains('headlessmc-web')
            }
        }))
    }

    reports {
        xml.required.set(true)
    }
}

allprojects {
    afterEvaluate {
        tasks.withType(GenerateMavenPom).configureEach {
            if (it.pom == null) {
                return
            }
            it.pom.withXml {
                asNode().dependencies.dependency.each { dependency ->
                    if (dependency.artifactId.last().value().last() in ['junit-jupiter-api', 'junit-jupiter-engine', 'forgecli']) {
                        assert dependency.parent().remove(dependency)
                    }
                }
            }
        }
    }
}

generateMetadataFileForHeadlessmcPublication.mustRunAfter(copyJars)
