package net.taehui.twilight.system

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import net.taehui.twilight.Logger
import net.taehui.twilight.TwilightComponent
import org.apache.commons.io.FilenameUtils
import java.io.IOException
import java.nio.file.Files
import java.util.*
import java.util.concurrent.ConcurrentHashMap

object EdgeSystem : Logger {
    class EdgeItem {
        var wwwLevel = ""
        var avatarLevel = 0
        var noteIDs: Array<String>? = null
        var wwwLevelCount = 0
    }

    private val edgeStore = ConcurrentHashMap<String, EdgeItem>()
    private val drawingStore = ConcurrentHashMap<String, ByteArray>()
    var isLoading = false

    fun getDrawing(edgeID: String): ByteArray? {
        return drawingStore[edgeID]
    }

    fun loadEdge() {
        isLoading = true
        try {
            edgeStore.clear()
            drawingStore.clear()
            Files.list(TwilightComponent.EDGE_ENTRY_PATH).use { edgeEntryPaths ->
                edgeEntryPaths.forEach { edgeEntryPath ->
                    try {
                        if (Files.isDirectory(edgeEntryPath)) {
                            Files.list(edgeEntryPath).use { edgeFilePaths ->
                                edgeFilePaths.forEach { edgeFilePath ->
                                    try {
                                        drawingStore[FilenameUtils.removeExtension(edgeFilePath.fileName.toString())] =
                                            Files.readAllBytes(edgeFilePath)
                                        logInfo("Loaded Edge (${edgeFilePath.fileName})")
                                    } catch (e: IOException) {
                                        logFault(e)
                                    }
                                }
                            }
                        } else if (edgeEntryPath.fileName.toString() == "Default.json") {
                            val jm = ObjectMapper()
                            val edgeData = TreeMap(
                                jm.readValue(edgeEntryPath.toFile(), object : TypeReference<Map<String, EdgeItem>>() {})
                            )
                            edgeStore.putAll(edgeData)
                            logInfo("Loaded Edge (${edgeEntryPath.fileName})")

                            jm.writerWithDefaultPrettyPrinter()
                                .writeValue(
                                    TwilightComponent.EDGE_ENTRY_PATH.resolve("Default.json").toFile(),
                                    edgeData
                                )
                            logInfo("Saved Edge (${edgeEntryPath.fileName})")
                        }
                    } catch (e: IOException) {
                        logFault(e)
                    }
                }
            }
        } catch (e: IOException) {
            logFault(e)
        } finally {
            isLoading = false
        }
    }

    fun getEdgeIDs(levelIDs: Collection<String>, noteIDs: Collection<String>, avatarLevel: Int): Collection<String> {
        return edgeStore.entries.filter { (_, edgeItem) ->
            edgeItem.avatarLevel <= avatarLevel &&
                    (edgeItem.wwwLevel.isEmpty() || levelIDs.any { it == edgeItem.wwwLevel }) &&
                    edgeItem.noteIDs?.all { noteID -> noteIDs.any { it == noteID } } != false &&
                    edgeItem.wwwLevelCount <= levelIDs.size
        }
            .map { it.key }
    }

    fun getEdgeIDs(levelID: String): Collection<String> {
        return edgeStore.entries.filter { (_, edgeItem) ->
            levelID == edgeItem.wwwLevel
        }.map { it.key }
    }
}