package net.taehui.twilight.system

import net.taehui.twilight.Logger
import net.taehui.twilight.TwilightComponent
import org.apache.commons.io.FilenameUtils
import java.nio.file.*
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit

object AutoSystem : Logger {
    private val ses: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor {
        Executors.defaultThreadFactory().newThread(it).apply {
            isDaemon = true
        }
    }
    private val ws = FileSystems.getDefault().newWatchService()
    private var futureVote: ScheduledFuture<*>? = null
    private var futureConfigure: ScheduledFuture<*>? = null
    private var futureAwilight: ScheduledFuture<*>? = null
    private var futureTitle: ScheduledFuture<*>? = null
    private var futureLevel: ScheduledFuture<*>? = null
    private var futureAbility: ScheduledFuture<*>? = null
    private var futureEdge: ScheduledFuture<*>? = null

    fun dispose() {
        ws.close()
        ses.shutdown()
    }

    fun handleSystem() {
        Thread {
            Paths.get(".").register(ws, StandardWatchEventKinds.ENTRY_MODIFY)
            TwilightComponent.SYSTEM_ENTRY_PATH.register(ws, StandardWatchEventKinds.ENTRY_MODIFY)
            TwilightComponent.DEFAULT_NOTE_ENTRY.register(ws, StandardWatchEventKinds.ENTRY_MODIFY)
            TwilightComponent.DEFAULT_UI_ENTRY.register(ws, StandardWatchEventKinds.ENTRY_MODIFY)
            TwilightComponent.TITLE_ENTRY_PATH.register(ws, StandardWatchEventKinds.ENTRY_MODIFY)
            TwilightComponent.LEVEL_ENTRY_PATH.register(ws, StandardWatchEventKinds.ENTRY_MODIFY)
            TwilightComponent.VOTE_ENTRY_PATH.register(ws, StandardWatchEventKinds.ENTRY_MODIFY)
            TwilightComponent.ABILITY_ENTRY_PATH.register(ws, StandardWatchEventKinds.ENTRY_MODIFY)
            TwilightComponent.EDGE_ENTRY_PATH.register(ws, StandardWatchEventKinds.ENTRY_MODIFY)
            var isAvailable = true
            while (isAvailable) {
                try {
                    val tws = ws.take()
                    tws.pollEvents().forEach {
                        fun loadConfigure() {
                            futureConfigure?.cancel(true)
                            futureConfigure = ses.schedule({
                                Configure.loadConfigure()
                            }, 1, TimeUnit.SECONDS)
                        }

                        val filePath = (tws.watchable() as Path).resolve(it.context() as Path)
                        val fileName = filePath.fileName.toString()
                        when (filePath.parent.fileName.toString()) {
                            "Note", "UI" -> {
                                if (FilenameUtils.isExtension(fileName, "zip") || FilenameUtils.isExtension(
                                        fileName,
                                        "rar"
                                    )
                                ) {
                                    loadConfigure()
                                }
                            }

                            "Vote" -> {
                                if (FilenameUtils.isExtension(fileName, "json") && !VoteSystem.isLoading) {
                                    futureVote?.cancel(true)
                                    futureVote = ses.schedule(
                                        { VoteSystem.loadVote() },
                                        1,
                                        TimeUnit.SECONDS
                                    )
                                }
                            }

                            "Title" -> {
                                if (FilenameUtils.isExtension(fileName, "json") && !TitleSystem.isLoading) {
                                    futureTitle?.cancel(true)
                                    futureTitle = ses.schedule(
                                        { TitleSystem.loadTitle() },
                                        1,
                                        TimeUnit.SECONDS
                                    )
                                }
                            }

                            "Level" -> {
                                if (FilenameUtils.isExtension(fileName, "json") && !LevelSystem.isLoading) {
                                    futureLevel?.cancel(true)
                                    futureLevel = ses.schedule(
                                        { LevelSystem.loadLevel() },
                                        1,
                                        TimeUnit.SECONDS
                                    )
                                }
                            }

                            "Ability" -> {
                                if (FilenameUtils.isExtension(fileName, "json") && !AbilitySystem.isLoading) {
                                    futureAbility?.cancel(true)
                                    futureAbility = ses.schedule(
                                        { AbilitySystem.loadAbility() },
                                        1,
                                        TimeUnit.SECONDS
                                    )
                                }
                            }

                            "Edge" -> {
                                if (FilenameUtils.isExtension(fileName, "json") && !EdgeSystem.isLoading) {
                                    futureEdge?.cancel(true)
                                    futureEdge = ses.schedule(
                                        { EdgeSystem.loadEdge() },
                                        1,
                                        TimeUnit.SECONDS
                                    )
                                }
                            }

                            "System" -> {
                                when (fileName) {
                                    "Awilight.py" -> {
                                        futureAwilight?.cancel(true)
                                        futureAwilight = ses.schedule(
                                            { AwilightHandler.loadAwilight() },
                                            1,
                                            TimeUnit.SECONDS
                                        )
                                    }
                                }
                            }

                            "." -> {
                                when (fileName) {
                                    "Configure.json" -> loadConfigure()
                                }
                            }
                        }
                    }
                    tws.reset()
                } catch (e: ClosedWatchServiceException) {
                    isAvailable = false
                } catch (e: InterruptedException) {
                    isAvailable = false
                }
            }
        }.apply { isDaemon = true }.start()
    }
}