package com.isidroid.gradle

import org.gradle.api.Project
import java.io.File
import java.util.concurrent.TimeUnit

private const val FOLDER_NAME = "release_builds"
private val BOT_TOKEN = "6723000441:AAEiBYPU-yzPih3j9gZGPHciqp8jHSa15xc"
private val CHAT_ID = "-1002108315874"
private val BOT_URL = "https://api.telegram.org/bot$BOT_TOKEN"

fun copyAllBundles(project: Project): File {
    val buildFolderName = "build"
    val outputsFolderName = "outputs"
    val apksFolderName = "apk"
    val bundlesFolderName = "bundle"

    cleanupBuilds(project)

    val listFiles = mutableListOf<File>()

    val appFolders = project.rootDir.listFiles().filter { it.isDirectory }

    for (appFolder in appFolders) {
        val bFolder = appFolder.listFiles().firstOrNull { it.name == buildFolderName } ?: continue
        val outputsFolder = bFolder.listFiles().firstOrNull { it.name == outputsFolderName } ?: continue

        val apkFolder = outputsFolder.listFiles().firstOrNull { it.name == apksFolderName }
        val bundleFolder = outputsFolder.listFiles().firstOrNull { it.name == bundlesFolderName }

        findAll(apkFolder, "apk", listFiles)
        findAll(bundleFolder, "aab", listFiles)
    }

    val buildFolder = File(project.rootDir, FOLDER_NAME)
    if (!buildFolder.exists())
        buildFolder.mkdirs()

    for (file in listFiles) {
        val newFile = File(buildFolder, file.name)
        file.copyTo(newFile, true)
    }


    return buildFolder
}

fun cleanupBuilds(project: Project) {
    val buildFolder = File(project.rootDir, FOLDER_NAME)
    if (buildFolder.exists())
        buildFolder.deleteRecursively()
}

private fun findAll(folder: File?, fileExt: String, listFiles: MutableList<File>) {
    folder ?: return
    val subFolders = folder.listFiles()
    for (file in subFolders) {
        if (file.isDirectory)
            findAll(file, fileExt, listFiles)
        else if (file.name.endsWith(".$fileExt"))
            listFiles.add(file)
    }
}

fun upload(file: File) {
    val allowExtensions = arrayOf("apk", "aab")
    val listFiles = file.listFiles()
        .filter { f ->
            val fileName = f.name
            val ext = fileName.split(".").lastOrNull().takeIf { fileName.contains(".") }
            allowExtensions.contains(ext)
        }

    for (build in listFiles) {
        val command = "curl -X POST $BOT_URL/sendDocument -F chat_id=$CHAT_ID -F document=@${build.absolutePath}"
        println("> send ${build.name}")
        val process = Runtime.getRuntime().exec(command.split(" ").toTypedArray())
        val result = process.inputReader().use { it.readText() }
        process.waitFor(10, TimeUnit.MINUTES)
        println("< complete result=$result")
    }
}


fun getBuildVersion(project: Project): Int {
    val inputFileProvider = project.layout.projectDirectory.file("version.properties")
    val inputFile = inputFileProvider.asFile
    return inputFile.readText().filter { it.isDigit() }.toIntOrNull() ?: 0
}

fun gitBranch(): String {
    return try {
        val command = "git rev-parse --abbrev-ref HEAD"
        executeSingleCommand(command)
            .also {
                if (it == "HEAD")
                    throw Exception("Unable to determine current branch: Project is checked out with detached head!")
            }

    } catch (e: Exception) {
        throw Exception("Unable to determine current branch: ${e.message}")
    }
}

fun increaseBuildNumber(project: Project) {
    val gitBranch = gitBranch()
    if (gitBranch == "release" || gitBranch == "master") {
        val version = getBuildVersion(project) + 1

        println("increaseBuildNumber version=$version")

        val versionFile = project.layout.projectDirectory.file("version.properties").asFile
        versionFile.printWriter().use { out -> out.println(version) }

        executeSingleCommand("git add $versionFile")
        execute("git", "commit", "-m", "\"bump_build_version_to_$version\"")
    }
}

fun createGitTag(project: Project, prefix: String) {
    val version = "${project.version}"
    println("createGitTag gitBranch=$version")

    execute("git", "tag", "-a", "$prefix/$version", "-m", "$prefix")
    execute("git", "push", "origin", gitBranch())
}

private fun execute(vararg command: String): String {
    val listCommands = command.toList()
    println("> ${listCommands.joinToString(" ")}")

    val process = Runtime.getRuntime().exec(listCommands.toTypedArray())
    return process.inputReader().use { it.readText() }.trim()
        .also { if (it.isNotBlank()) println("< $it") }
}

private fun executeSingleCommand(command: String): String {
    return execute(*command.split(" ").toTypedArray())
}