plugins{
    id 'java-library'
}

sourceSets.main{
    java.srcDirs = [
        'src/',
        "${compileJava.temporaryDir}/fetched",
        "$buildDir/generated/sources/annotationProcessor/java/main/"
    ]
}

sourceCompatibility = 16
targetCompatibility = 8

dependencies{

    compileOnly "com.github.Anuken.MindustryJitpack:core:$mindustryVersion"
    compileOnly "com.github.Anuken.Arc:arc-core:$arcVersion"
    compileOnly project(':annotations')
    annotationProcessor project(':annotations')
    annotationProcessor "com.github.Anuken:jabel:$jabelVersion"
}

ext{
    fetchPackage = 'unity/fetched'
    fetchDir = file("${compileJava.temporaryDir}/fetched/$fetchPackage")
    fetchTemp = file("${compileJava.temporaryDir}/fetch.txt")
    fetchRevision = 0
}

import arc.files.*
import arc.func.*
import arc.struct.*
import arc.util.*
import arc.util.serialization.*

import java.util.concurrent.*

task deploy(type: Jar, dependsOn: configurations.runtimeClasspath){
    if(!spritesDir.exists()){
        finalizedBy ':tools:proc'
        if(taskNames.contains('main:deploy')) println 'Sprites folder not found; automatically generating sprites...'
    }

    archiveFileName.set "${modName}Desktop.jar"

    from files(sourceSets.main.output.classesDirs)
    from files(sourceSets.main.output.resourcesDir)
    from configurations.runtimeClasspath.collect{ it.isDirectory() ? it : zipTree(it) }
    from files(assetsDir){ exclude 'sprites/vanilla/**' }

    from(rootDir){
        include 'mod.json'
        include 'icon.png'
    }

    doFirst{
        println "Deploying ${devBuild ? 'dev' : 'user'} build."
    }
}

task dex(type: Jar){
    archiveFileName.set "${modName}.jar"

    final def desktopJar = deploy.archiveFile.get().asFile
    final def dexJar = new File(dex.temporaryDir, 'Dexed.jar')

    if(!desktopJar.exists() || taskNames.contains('main:deploy')) dependsOn deploy
    doFirst{
        println 'Dexifying...'
        def command = ['d8', '--min-api', sdkAPI, '--output', dexJar, desktopJar]
        final File[] files =
            configurations.compileClasspath.asList() +
            configurations.runtimeClasspath.asList()

        for(def file : files) command += ['--classpath', file.path]
        command += ['--lib', file("$sdkRoot/platforms/android-$sdkVersion/android.jar")]

        if(OS.isWindows) command = ['cmd', '/c'] + command
        command.join(' ').execute(null, new File("$buildDir/libs")).waitForProcessOutput(System.out, System.err)
    }

    from zipTree(desktopJar)
    from zipTree(dexJar)
}

task dmove(dependsOn: deploy){
    doLast{
        copy{
            from "build/libs/ProjectUnityDesktop.jar"
            into System.getenv("destination")
        }
    }
}

class Fetcher{
    UnsafeRunnable run

    private volatile Throwable error = null

    @SuppressWarnings('all')
    void execute(){
        Boolf<UnsafeRunnable> exec = { final UnsafeRunnable run ->
            try{
                run.run()
                error = null
            }catch(Throwable e){
                Log.err(e)
                error = e
            }

            return error != null
        }

        exec.get(run)
    }
}

task fetchComps{
    doFirst{
        delete{ delete fetchDir }
        fetchDir.mkdir()

        final CopyOnWriteArrayList<Fetcher> fetches = new CopyOnWriteArrayList<>()

        UnsafeRunnable mainRun ={
            Http.get("https://api.github.com/repos/Anuken/Mindustry/contents/core/src/mindustry/entities/comp?ref=$mindustryFetchVersion")
                .error({ final t -> throw new RuntimeException(t) })
                .block({ final res ->
                    final def list = Jval.read(res.getResultAsString()).asArray()
                    println "Found $list.size entity components."

                    for(final Jval val : list){
                        final def filename = val.get('name').asString()
                        final def fileurl = val.get('download_url').asString()

                        final UnsafeRunnable run ={
                            Http.get(fileurl)
                                .error({ final t -> throw new RuntimeException(t) })
                                .block({ final comp ->
                                    final def content = comp.getResultAsString()
                                        .replace('mindustry.entities.comp', fetchPackage.replace('/', '.'))
                                        .replace('mindustry.annotations.Annotations.*', 'unity.annotations.Annotations.*')
                                        .replaceAll('@Component\\((base = true|.)+\\)\n*', '@EntityComponent(base = true, write = false)\n')
                                        .replaceAll('@Component\n*', '@EntityComponent(write = false)\n')
                                        .replaceAll('@BaseComponent\n*', '@EntityBaseComponent\n')
                                        .replaceAll('@CallSuper\n*', '')
                                        .replaceAll('@Final\n*', '')
                                        .replaceAll('@EntityDef\\(*.*\\)*\n*', '')

                                    if(content.isEmpty()) throw new IllegalStateException()

                                    final def fi = Fi.get("$fetchDir/$filename")
                                    fi.writeString(content, false)
                                })
                        }

                        fetches.add(new Fetcher(run: run))
                    }
                })
        }

        new Fetcher(run: mainRun).execute()

        final def found = fetches.size()

        Seq<Thread> threads = Seq.with(fetches).map({ final Fetcher fetch -> new Thread({
            fetch.execute()
            synchronized(fetches){
                fetches.remove(fetch)
                print '\b'
            }
        }) })

        threads.each(Thread::start)
        while(!fetches.isEmpty()) Thread.currentThread().yield()

        fetchTemp.text = "$mindustryVersion/$fetchRevision"
        println "Wrote $found entity components."
    }
}

task cleanFetched(type: Delete){
    delete "$projectDir/fetched"
    delete "$fetchTemp"
}

task assetsJar(type: Jar){
    archiveClassifier.set 'assets'
    from files('assets/')
}

artifacts{
    archives assetsJar
}

tasks.withType(JavaCompile){
    if(!fetchDir.exists() || !fetchTemp.exists()){
        dependsOn fetchComps
    }else{
        String[] content = fetchTemp.text.split('/')
        String ver = content[0]
        String rev = content[1]

        if(ver != "$mindustryVersion" as String || rev != Integer.toString(fetchRevision as int)){
            dependsOn fetchComps
        }
    }

    options.compilerArgs += ['--release', '8']
}

tasks.withType(Jar){
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE

    exclude 'unity/fetched/**'
    exclude 'unity/entities/comp/**'
    exclude 'unity/entities/merge/**'
    if(!devBuild) exclude 'unity/mod/DevBuildImpl*'

    exclude 'sprites/vanilla/**'
}
