package net.taehui.twilight.system

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import net.taehui.twilight.JSON
import net.taehui.twilight.Logger
import net.taehui.twilight.TwilightComponent
import java.io.IOException
import java.nio.file.Files
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.stream.Collectors

object TitleSystem : Logger {
    class TitleItem : Comparable<TitleItem> {
        var title = ""
        var title1042 = ""
        var titleColor = ""
        var wwwLevel = ""
        var avatarLevel = 0
        var noteIDs: Array<String>? = null
        var titleLevel = 0

        override fun compareTo(other: TitleItem): Int {
            val avatarLevelData = avatarLevel.compareTo(other.avatarLevel)
            if (avatarLevelData != 0) {
                return avatarLevelData
            }
            val levelItem0 = LevelSystem.getLevelItem(wwwLevel)
            val levelItem1 = LevelSystem.getLevelItem(other.wwwLevel)
            if (levelItem0 != null && levelItem1 != null) {
                val levelData = levelItem0.compareTo(levelItem1)
                if (levelData != 0) {
                    return levelData
                }
            }
            val titleData = title.compareTo(other.title)
            return if (titleData != 0) {
                titleData
            } else {
                titleLevel.compareTo(other.titleLevel)
            }
        }
    }

    private val titleStore = ConcurrentHashMap<String, TitleItem>()
    var isLoading = false

    fun loadTitle() {
        isLoading = true
        try {
            titleStore.clear()
            Files.list(TwilightComponent.TITLE_ENTRY_PATH).use { titleFilePaths ->
                titleFilePaths.forEach { titleFilePath ->
                    try {
                        val jm = ObjectMapper()
                        val titleItems =
                            jm.readValue(titleFilePath.toFile(), object : TypeReference<Map<String, TitleItem>>() {})
                        val titleData = TreeMap<String, TitleItem>(Comparator.comparing { titleItems[it]!! })
                        titleData.putAll(titleItems)
                        titleStore.putAll(titleData)
                        logInfo("Loaded Title (${titleFilePath.fileName})")

                        jm.writerWithDefaultPrettyPrinter().writeValue(titleFilePath.toFile(), titleData)
                        logInfo("Saved Title (${titleFilePath.fileName})")
                    } catch (e: IOException) {
                        logFault(e)
                    }
                }
            }
        } catch (e: IOException) {
            logFault(e)
        } finally {
            isLoading = false
        }
    }

    fun getTitle(language: String, titleID: String): JSON.TwilightWwwTitle? {
        val titleItem = titleStore[titleID]
        return if (titleItem != null) JSON.TwilightWwwTitle(
            when (language) {
                "ko-KR" -> titleItem.title1042
                else -> titleItem.title
            }, titleItem.titleColor
        ) else null
    }

    fun getTitles(
        levelIDs: Collection<String>, noteIDs: Collection<String>, avatarLevel: Int, language: String
    ): Collection<Any> {
        return getTitleIDs(levelIDs, noteIDs, avatarLevel).stream().sorted { o1, o2 ->
            val titleItem1 = titleStore[o1]!!
            val titleItem2 = titleStore[o2]!!
            val titleColorData = titleItem1.titleColor.compareTo(titleItem2.titleColor)
            if (titleColorData != 0) titleColorData else titleItem1.compareTo(titleItem2)
        }.map {
            val titleItem = titleStore[it]!!

            object {
                val titleID = it
                val title = when (language) {
                    "ko-KR" -> titleItem.title1042
                    else -> titleItem.title
                }
                val titleColor = titleItem.titleColor
            }
        }.toList()
    }

    fun getTitleItems(
        levelIDs: Collection<String>, noteIDs: Collection<String>, avatarLevel: Int
    ): Collection<TitleItem> {
        return getTitleIDs(levelIDs, noteIDs, avatarLevel).mapNotNull { titleStore[it] }
    }

    fun getTitleIDs(levelIDs: Collection<String>, noteIDs: Collection<String>, avatarLevel: Int): Collection<String> {
        val titleIDs = mutableListOf<String>()
        titleStore.entries.stream().filter { (_, titleItem) ->
            titleItem.avatarLevel <= avatarLevel && (titleItem.wwwLevel.isEmpty() || levelIDs.any { it == titleItem.wwwLevel }) && titleItem.noteIDs?.all { noteID -> noteIDs.any { it == noteID } } != false
        }.collect(Collectors.groupingBy { it.value.title }).values.forEach { titleItems ->
            if (titleItems.size > 1) {
                titleIDs.add(titleItems.maxBy { it.value.titleLevel }.key)
            } else {
                titleIDs.add(titleItems[0].key)
            }
        }
        return titleIDs
    }

    fun getTitles(levelID: String, language: String): Array<Any> {
        val titleIDs = mutableListOf<String>()
        titleStore.entries.stream().filter { (_, titleItem) -> levelID == titleItem.wwwLevel }
            .collect(Collectors.groupingBy { it.value.title }).values.forEach { titleItems ->
                if (titleItems.size > 1) {
                    titleIDs.add(titleItems.maxBy { it.value.titleLevel }.key)
                } else {
                    titleIDs.add(titleItems[0].key)
                }
            }
        return titleIDs.map {
            val titleItem = titleStore[it]!!

            object {
                val titleID = it
                val title = when (language) {
                    "ko-KR" -> titleItem.title1042
                    else -> titleItem.title
                }
                val titleColor = titleItem.titleColor
            }
        }.toTypedArray()
    }
}