/*
 * 第 5 章 · Task 全攻略 — 完整可跑示例
 *
 * 包含：
 *   - 三种 Task 写法（doLast / Typed / 自定义类）
 *   - 增量构建（input/output 声明）
 *   - 增量处理输入文件（@Incremental + InputChanges）
 *   - Provider 链式
 *   - onlyIf / enabled 控制执行
 *
 * 跑：
 *   ./gradlew tasks --group ch05-demo
 *   ./gradlew renderTemplates       —— 看增量构建效果（再跑一次会 UP-TO-DATE）
 *   ./gradlew countLines             —— 自定义 Task 类示例
 *   ./gradlew generateBuildInfo      —— 生成 BuildInfo.java
 *   ./gradlew releaseZip             —— 综合：依赖链 + Typed Task
 */

import org.gradle.work.Incremental
import org.gradle.work.InputChanges
import org.gradle.work.ChangeType

plugins {
    base
}

version = "1.0.0"

// ===========================================================================
// 写法 1：临时 Task（doLast）
// 没声明 input/output → 每次都跑（演示反面教材）
// ===========================================================================
tasks.register("badTask") {
    group = "ch05-demo"
    description = "反面教材：每次都全量执行的 Task"
    doLast {
        println("⏰ Bad task: 我每次都被执行（即使没改任何东西）")
        Thread.sleep(800)
    }
}

// ===========================================================================
// 写法 1+：临时 Task + input/output 声明 → 增量构建生效
// ===========================================================================
tasks.register("renderTemplates") {
    group = "ch05-demo"
    description = "增量构建演示：渲染 templates/ 下的所有文件"

    val srcDir = layout.projectDirectory.dir("templates")
    val outDir = layout.buildDirectory.dir("rendered")

    inputs.dir(srcDir).optional()
    inputs.property("name", "World")
    outputs.dir(outDir)

    doLast {
        if (!srcDir.asFile.exists()) {
            srcDir.asFile.mkdirs()
            srcDir.asFile.resolve("hello.txt").writeText("Hello, {{name}}!")
        }
        outDir.get().asFile.mkdirs()
        srcDir.asFile.listFiles().orEmpty().forEach { f ->
            val rendered = f.readText().replace("{{name}}", "World")
            outDir.get().file(f.name).asFile.writeText(rendered)
        }
        println("✅ Rendered " + srcDir.asFile.listFiles().orEmpty().size + " templates")
    }
}

// ===========================================================================
// 写法 2：Typed Task —— 用内置类型
// ===========================================================================
tasks.register<Copy>("copyDocs") {
    group = "ch05-demo"
    description = "演示 Copy 类型"

    from("docs") {
        include("**/*.md")
    }
    into(layout.buildDirectory.dir("docs"))
}

tasks.register<Zip>("releaseZip") {
    group = "ch05-demo"
    description = "综合演示：聚合多个产物为 zip"

    dependsOn("copyDocs", "renderTemplates")
    archiveFileName = "release-" + project.version + ".zip"
    destinationDirectory = layout.buildDirectory.dir("releases")

    from(layout.buildDirectory.dir("docs")) { into("docs") }
    from(layout.buildDirectory.dir("rendered")) { into("rendered") }
}

// ===========================================================================
// 写法 3：自定义 Task 类（推荐）
// ===========================================================================
@CacheableTask
abstract class CountLinesTask : DefaultTask() {

    @get:InputDirectory
    @get:PathSensitive(PathSensitivity.RELATIVE)
    abstract val sourceDir: DirectoryProperty

    @get:Input
    abstract val fileExtension: Property<String>

    @get:OutputFile
    abstract val report: RegularFileProperty

    @TaskAction
    fun count() {
        val pattern = "**/*." + fileExtension.get()
        val files = sourceDir.get().asFileTree.matching { include(pattern) }.files
        val total = files.sumOf { it.readLines().size }

        report.get().asFile.parentFile.mkdirs()
        report.get().asFile.writeText("Files: " + files.size + "\nTotal lines: " + total + "\n")
        println("📊 Counted " + total + " lines in " + files.size + " files → " + report.get().asFile)
    }
}

tasks.register<CountLinesTask>("countLines") {
    group = "ch05-demo"
    description = "统计 Kotlin 源码行数"
    sourceDir = layout.projectDirectory
    fileExtension = "kts"
    report = layout.buildDirectory.file("reports/lines.txt")
}

// ===========================================================================
// 自定义 Task：生成 BuildInfo.java（典型代码生成场景）
// ===========================================================================
abstract class GenerateBuildInfoTask : DefaultTask() {
    @get:Input
    abstract val packageName: Property<String>

    @get:Input
    abstract val version: Property<String>

    @get:OutputDirectory
    abstract val outputDir: DirectoryProperty

    @TaskAction
    fun generate() {
        val pkg = packageName.get()
        val pkgPath = pkg.replace('.', '/')
        val target = outputDir.get().asFile.resolve(pkgPath + "/BuildInfo.java")
        target.parentFile.mkdirs()

        target.writeText("""
            package $pkg;
            public final class BuildInfo {
                public static final String VERSION = "${'$'}{version.get()}";
                public static final String BUILD_TIME = "${'$'}{System.currentTimeMillis()}";
                private BuildInfo() {}
            }
        """.trimIndent())

        println("📝 Generated: " + target.absolutePath)
    }
}

tasks.register<GenerateBuildInfoTask>("generateBuildInfo") {
    group = "ch05-demo"
    description = "生成 BuildInfo.java 类（演示代码生成）"
    packageName = "com.example.generated"
    version = project.version.toString()
    outputDir = layout.buildDirectory.dir("generated/sources/buildInfo/java")
}

// ===========================================================================
// 增量处理输入文件：@Incremental + InputChanges
// ===========================================================================
abstract class TransformFilesTask : DefaultTask() {
    @get:InputDirectory
    @get:Incremental
    @get:PathSensitive(PathSensitivity.RELATIVE)
    abstract val src: DirectoryProperty

    @get:OutputDirectory
    abstract val dst: DirectoryProperty

    @TaskAction
    fun execute(changes: InputChanges) {
        if (!changes.isIncremental) {
            println("🔄 Full rebuild")
            dst.get().asFile.deleteRecursively()
            dst.get().asFile.mkdirs()
        } else {
            println("⚡ Incremental rebuild")
        }

        changes.getFileChanges(src).forEach { c ->
            val target = dst.get().file(c.normalizedPath).asFile
            when (c.changeType) {
                ChangeType.ADDED, ChangeType.MODIFIED -> {
                    target.parentFile.mkdirs()
                    target.writeText(c.file.readText().uppercase())
                    println("  📝 " + c.changeType + ": " + c.normalizedPath)
                }
                ChangeType.REMOVED -> {
                    target.delete()
                    println("  ❌ REMOVED: " + c.normalizedPath)
                }
            }
        }
    }
}

tasks.register<TransformFilesTask>("transformFiles") {
    group = "ch05-demo"
    description = "增量处理：只对变化的文件做转换"
    src = layout.projectDirectory.dir("data")
    dst = layout.buildDirectory.dir("transformed")
}

// ===========================================================================
// 演示 onlyIf
// ===========================================================================
tasks.register("uploadToS3") {
    group = "ch05-demo"
    description = "只在 -Prelease 时执行"
    onlyIf { project.hasProperty("release") }
    doLast { println("📤 Uploading to S3...") }
}

// ===========================================================================
// 演示 finalizedBy
// ===========================================================================
tasks.register("riskyOperation") {
    group = "ch05-demo"
    description = "演示 finalizedBy：A 跑完后无论成败都跑 cleanup"
    finalizedBy("cleanup")
    doLast { println("⚠️  Risky operation running...") }
}
tasks.register("cleanup") {
    group = "ch05-demo"
    doLast { println("🧹 Cleanup running (always after riskyOperation)") }
}
