/* Copyright 2025-2026 Eugene Petrenko (mcp@jonnyzzz.com); Copyright 2025-2026 JetBrains. Use of this source code is governed by the Apache 2.0 license. */
package com.jonnyzzz.mcpSteroid.gradle

import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.buildCodeBlock
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import kotlin.math.absoluteValue

abstract class GenerateMetadataTask : DefaultTask() {
    @get:Input
    abstract val versionString: Property<String>

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

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

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

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

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

    @get:OutputFile
    abstract val outputFile: RegularFileProperty

    init {
        packageName.convention("com.jonnyzzz.mcpSteroid")
        fileName.convention("PluginMetadata")
        functionName.convention("getPluginVersion")
        objectName.convention("")
        functionKdoc.convention("Plugin version (encoded)")
    }

    @TaskAction
    fun generate() {
        // Seed from the version string so encoding is deterministic for identical inputs.
        // A random seed would make the output differ on every run even if the version didn't
        // change, defeating Gradle's up-to-date checks and forcing full recompilation every
        // time (observed: +20 s per TDD iteration with a random seed).
        val baseMagic = (versionString.get().hashCode().absoluteValue + 237) % 19456

        fun String.toEncodedSequence(): List<Int> {
            return reversed().map { it.code * baseMagic }
        }

        val versionCodes = versionString.get().toEncodedSequence()

        val suppressAnnotation = AnnotationSpec.builder(Suppress::class)
            .addMember("%S, %S, %S", "MagicNumber", "unused", "NOTHING_TO_INLINE")
            .build()

        val versionFun = FunSpec.builder(functionName.get())
            .addModifiers(KModifier.INLINE)
            .returns(String::class)
            .addKdoc(functionKdoc.get())
            .addCode(buildCodeBlock {
                beginControlFlow("return sequence")
                versionCodes.forEach { code ->
                    addStatement("yield(%L)", code)
                }
                unindent()
                add("}.map { it / %L }.toList().reversed().map { it.toChar() }.joinToString(%S)\n", baseMagic, "")
            })
            .build()

        val objectName = objectName.get().trim()
        val fileSpecBuilder = FileSpec.builder(packageName.get(), fileName.get())
            .addFileComment("Auto-generated by Gradle - DO NOT EDIT")
            .addAnnotation(suppressAnnotation)
        val fileSpec = if (objectName.isEmpty()) {
            fileSpecBuilder.addFunction(versionFun).build()
        } else {
            fileSpecBuilder
                .addType(TypeSpec.objectBuilder(objectName).addFunction(versionFun).build())
                .build()
        }

        val file = outputFile.get().asFile
        file.parentFile.mkdirs()
        file.writeText(fileSpec.toString())
    }
}
