/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.nio.file.Files
import java.nio.file.Paths
import java.io.FileOutputStream
import java.util.zip.ZipFile

// Android tasks for Javadoc and sources.jar generation

afterEvaluate { project ->
    if (POM_PACKAGING == 'aar') {
        task androidJavadoc(type: Javadoc, dependsOn: assembleDebug) {
            source += files(android.sourceSets.main.java.srcDirs)
            failOnError false
            // This task will try to compile *everything* it finds in the above directory and
            // will choke on text files it doesn't understand.
            exclude '**/BUCK'
            exclude '**/*.md'
        }

        task androidJavadocJar(type: Jar, dependsOn: androidJavadoc) {
            archiveClassifier.set('javadoc')
            from androidJavadoc.destinationDir
        }

        task androidSourcesJar(type: Jar) {
            archiveClassifier.set('sources')
            from android.sourceSets.main.java.srcDirs
        }

        android.libraryVariants.all { variant ->
            def name = variant.name.capitalize()
            task "jar${name}"(type: Jar, dependsOn: variant.javaCompileProvider) {
                from variant.javaCompileProvider.get().destinationDir
            }

            androidJavadoc.doFirst {
                classpath += files(android.bootClasspath)
                classpath += files(variant.javaCompileProvider.get().classpath.files)
                // This is generated by `assembleDebug` and holds the JARs generated by the APT.
                classpath += fileTree(dir: "$buildDir/intermediates/bundles/debug/", include: '**/*.jar')

                // Process AAR dependencies
                def aarDependencies = classpath.filter { it.name.endsWith('.aar') }
                classpath -= aarDependencies
                aarDependencies.each { aar ->
                    // Extract classes.jar from the AAR dependency, and add it to the javadoc classpath
                    def outputPath = "$buildDir/tmp/aarJar/${aar.name.replace('.aar', '.jar')}"
                    classpath += files(outputPath)

                    // Use a task so the actual extraction only happens before the javadoc task is run
                    dependsOn task(name: "extract ${aar.name}").doLast {
                        extractEntry(aar, 'classes.jar', outputPath)
                    }
                }
            }
        }

        artifacts.add('archives', androidJavadocJar)
        artifacts.add('archives', androidSourcesJar)
    }

    if (POM_PACKAGING == 'jar') {
        task javadocJar(type: Jar, dependsOn: javadoc) {
            archiveClassifier.set('javadoc')
            from javadoc.destinationDir
        }

        task sourcesJar(type: Jar, dependsOn: classes) {
            archiveClassifier.set('sources')
            from sourceSets.main.allSource
        }

        artifacts.add('archives', javadocJar)
        artifacts.add('archives', sourcesJar)
    }
}

// Utility method to extract only one entry in a zip file
private def extractEntry(archive, entryPath, outputPath) {
    if (!archive.exists()) {
        throw new GradleException("archive $archive not found")
    }

    def zip = new ZipFile(archive)
    zip.entries().each {
        if (it.name == entryPath) {
            def path = Paths.get(outputPath)
            if (!Files.exists(path)) {
                Files.createDirectories(path.getParent())
                Files.copy(zip.getInputStream(it), path)
            }
        }
    }
    zip.close()
}
