apply plugin: 'jacoco'

jacoco {
    toolVersion(versions.jacoco)
}

def mergedJacocoExec = file("${project.buildDir}/jacoco/jacocoMerged.exec")

tasks.create(name: 'jacocoMergeReports', type: JacocoMerge) {
    group = "Reporting"
    description = "Merge all jacoco reports from projects into one."

    ListProperty<File> jacocoFiles = project.objects.listProperty(File.class)
    project.subprojects { subproject ->
        subproject.plugins.withId("jacoco") {
            project.logger.info("${subproject.name} has Jacoco plugin applied")
            subproject.tasks.withType(Test) { task ->
                File destFile = task.extensions.getByType(JacocoTaskExtension.class).destinationFile
                if (destFile.exists() && !task.name.contains("Release")) {
                    jacocoFiles.add(destFile)
                }
            }
        }
    }

    executionData(jacocoFiles)
    destinationFile(mergedJacocoExec)
}

tasks.create(name: 'jacocoFullReport', type: JacocoReport, dependsOn: 'jacocoMergeReports') {
    group = "Reporting"
    description = "Generate full Jacoco coverage report including all modules."

    getClassDirectories().setFrom(files())
    getSourceDirectories().setFrom(files())
    getExecutionData().setFrom(files())

    reports {
        xml.enabled = true
        html.enabled = true
        csv.enabled = false
    }

    // Always run merging, as all input calculation is done in doFirst {}
    outputs.upToDateWhen { false }
    // Task will run anyway even if initial inputs are empty
    onlyIf = { true }

    doFirst {
        project.subprojects { subproject ->
            subproject.plugins.withId("jacoco") {
                project.logger.info("${subproject.name} has Jacoco plugin applied")
                subproject.plugins.withId("kotlin-android") {
                    project.logger.info("${subproject.name} is android project")
                    def mainSources = subproject.extensions.findByName("android").sourceSets['main']
                    project.logger.info("Android sources: ${mainSources.java.srcDirs}")
                    mainSources.java.srcDirs.forEach {
                        additionalSourceDirs(it)
                    }
                    project.logger.info("Subproject exclude: ${subproject.jacocoExclude}")
                    additionalClassDirs(fileTree(
                            dir: "${subproject.buildDir}/tmp/kotlin-classes/debug",
                            excludes: subproject.jacocoExclude
                    ))
                }
                subproject.plugins.withId("kotlin") { plugin ->
                    project.logger.info("${subproject.name} is common kotlin project")
                    SourceDirectorySet mainSources = subproject.extensions.getByName("kotlin")
                            .sourceSets[SourceSet.MAIN_SOURCE_SET_NAME]
                            .kotlin
                    mainSources.srcDirs.forEach {
                        project.logger.debug("Adding sources: $it")
                        additionalSourceDirs(it)
                    }
                    project.logger.info("Subproject exclude: ${subproject.jacocoExclude}")
                    additionalClassDirs(fileTree(
                            dir: "${subproject.buildDir}/classes/kotlin/main",
                            excludes: subproject.jacocoExclude
                    ))
                }

                subproject.tasks.withType(Test) { task ->
                    File destFile = task.extensions.getByType(JacocoTaskExtension.class).destinationFile
                    if (destFile.exists() && !task.name.contains("Release")) {
                        project.logger.info("Adding execution data: $destFile")
                        executionData(destFile)
                    }
                }
            }
        }
    }
}
