package com.demoscene.tv.data
import android.content.Context
import android.util.Log
import com.demoscene.tv.model.Demo
import com.demoscene.tv.model.CategoryRow
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.Calendar

object DemoDataProvider {
    
    suspend fun getCategoryRows(context: Context): List<CategoryRow> = withContext(Dispatchers.IO) {
        try {
            val dump = PouetCache.loadFromCache(context)
            val prods = dump?.prods ?: emptyList()
            Log.d("DemosceneTV", "Loaded " + prods.size.toString() + " productions")
            val allDemos = prods.mapNotNull { prod -> convertToDemo(prod) }
            Log.d("DemosceneTV", "Converted to " + allDemos.size.toString() + " demos")
            if (allDemos.isEmpty()) return@withContext emptyList()
            val categories = mutableListOf<CategoryRow>()
            categories.add(CategoryRow("Top Rated All Time", allDemos.sortedByDescending { it.rating }.take(200)))
            categories.add(CategoryRow("Recent Demos", allDemos.sortedByDescending { it.year }.take(200)))
            categories.add(CategoryRow("Random Selection", allDemos.shuffled().take(100)))
            val demoList = allDemos.filter { it.type.contains("demo", true) }.shuffled()
            if (demoList.size >= 20) categories.add(CategoryRow("Demos", demoList.take(200)))
            val intro64k = allDemos.filter { it.type.contains("64", true) }.shuffled()
            if (intro64k.size >= 20) categories.add(CategoryRow("64k Intros", intro64k.take(200)))
            val intro4k = allDemos.filter { it.type.contains("4", true) && !it.type.contains("64", true) }.shuffled()
            if (intro4k.size >= 20) categories.add(CategoryRow("4k Intros", intro4k.take(200)))
            val intro256 = allDemos.filter { it.type.contains("256", true) || it.type.contains("byte", true) }.shuffled()
            if (intro256.size >= 10) categories.add(CategoryRow("256b & Tiny Intros", intro256.take(100)))
            val byPlatform = allDemos.groupBy { it.platform }
            byPlatform.entries
                .filter { it.value.size >= 20 }
                .sortedByDescending { it.value.size }
                .take(10)
                .forEach { (platform, demos) ->
                    categories.add(CategoryRow(platform, demos.shuffled().take(200)))
                }
            val currentYear = Calendar.getInstance().get(Calendar.YEAR)
            for (year in currentYear downTo 2020) {
                val yearDemos = allDemos.filter { it.year == year }.shuffled()
                if (yearDemos.size >= 10) {
                    categories.add(CategoryRow(year.toString(), yearDemos.take(200)))
                }
            }
            val byDecade = allDemos.filter { it.year < 2020 }.groupBy { (it.year / 10) * 10 }
            byDecade.entries
                .filter { it.key > 1980 && it.value.size >= 20 }
                .sortedByDescending { it.key }
                .forEach { (decade, demos) ->
                    categories.add(CategoryRow(decade.toString() + "s", demos.shuffled().take(200)))
                }
            Log.d("DemosceneTV", "Created " + categories.size.toString() + " categories")
            categories
        } catch (e: Exception) {
            Log.e("DemosceneTV", "Error: " + (e.message ?: "Unknown"), e)
            emptyList()
        }
    }
    
    // Search by group name
    suspend fun searchByGroup(context: Context, groupName: String): List<Demo> = withContext(Dispatchers.IO) {
        try {
            val dump = PouetCache.loadFromCache(context)
            val prods = dump?.prods ?: emptyList()
            val allDemos = prods.mapNotNull { prod -> convertToDemo(prod) }
            
            val groupDemos = allDemos.filter { demo ->
                demo.group.equals(groupName, ignoreCase = true)
            }.sortedByDescending { it.rating }
            
            Log.d("DemosceneTV", "Found ${groupDemos.size} demos by group: $groupName")
            groupDemos
        } catch (e: Exception) {
            Log.e("DemosceneTV", "Error searching by group: ${e.message}", e)
            emptyList()
        }
    }
    
    // General search - searches title, group, platform
    suspend fun search(context: Context, query: String): List<Demo> = withContext(Dispatchers.IO) {
        try {
            if (query.isBlank()) return@withContext emptyList()
            
            val dump = PouetCache.loadFromCache(context)
            val prods = dump?.prods ?: emptyList()
            val allDemos = prods.mapNotNull { prod -> convertToDemo(prod) }
            val queryLower = query.lowercase().trim()
            
            val results = allDemos.filter { demo ->
                demo.title.lowercase().contains(queryLower) ||
                demo.group.lowercase().contains(queryLower) ||
                demo.platform.lowercase().contains(queryLower)
            }.sortedByDescending { it.rating }.take(200)
            
            Log.d("DemosceneTV", "Search '$query' found ${results.size} results")
            results
        } catch (e: Exception) {
            Log.e("DemosceneTV", "Error searching: ${e.message}", e)
            emptyList()
        }
    }
    
    private fun convertToDemo(prod: PouetProd): Demo? {
        try {
            val id = prod.id ?: return null
            val name = prod.name ?: return null
            val youtubeLink = extractYoutubeLink(prod.downloadLinks) ?: return null
            val group = extractGroupName(prod.groups)
            val platform = extractPlatformName(prod.platforms)
            val year = prod.releaseDate?.substring(0, 4)?.toIntOrNull() ?: 0
            val voteUp = prod.voteup ?: 0
            val votePig = prod.votepig ?: 0
            val voteDown = prod.votedown ?: 0
            val rating = calculateRating(voteUp, votePig, voteDown)
            return Demo(
                id = id,
                title = name,
                group = group,
                year = year,
                platform = platform,
                type = prod.type ?: "demo",
                party = null,
                rating = rating,
                youtubeUrl = youtubeLink,
                thumbnailUrl = prod.screenshot ?: "",
                pouetUrl = "https://www.pouet.net/prod.php?which=" + id,
                description = "",
                voteUp = voteUp
            )
        } catch (e: Exception) {
            return null
        }
    }
    
    private fun extractYoutubeLink(linksElement: com.google.gson.JsonElement?): String? {
        try {
            if (linksElement == null || !linksElement.isJsonArray) return null
            for (linkElement in linksElement.asJsonArray) {
                if (!linkElement.isJsonObject) continue
                val linkObj = linkElement.asJsonObject
                val type = linkObj.get("type")?.asString
                if (type == "youtube") return linkObj.get("link")?.asString
            }
        } catch (e: Exception) {}
        return null
    }
    
    private fun extractGroupName(groupsElement: com.google.gson.JsonElement?): String {
        try {
            if (groupsElement == null) return "Unknown"
            if (groupsElement.isJsonArray) {
                val firstGroup = groupsElement.asJsonArray.firstOrNull()
                if (firstGroup?.isJsonObject == true) {
                    return firstGroup.asJsonObject.get("name")?.asString ?: "Unknown"
                }
            } else if (groupsElement.isJsonObject) {
                return groupsElement.asJsonObject.get("name")?.asString ?: "Unknown"
            }
        } catch (e: Exception) {}
        return "Unknown"
    }
    
    private fun extractPlatformName(platformsElement: com.google.gson.JsonElement?): String {
        try {
            if (platformsElement == null) return "Unknown"
            if (platformsElement.isJsonObject) {
                val firstKey = platformsElement.asJsonObject.keySet().firstOrNull()
                if (firstKey != null) {
                    return platformsElement.asJsonObject.get(firstKey)?.asJsonObject?.get("name")?.asString ?: "Unknown"
                }
            } else if (platformsElement.isJsonArray) {
                val firstPlatform = platformsElement.asJsonArray.firstOrNull()
                if (firstPlatform?.isJsonObject == true) {
                    return firstPlatform.asJsonObject.get("name")?.asString ?: "Unknown"
                }
            }
        } catch (e: Exception) {}
        return "Unknown"
    }
    
    private fun calculateRating(up: Int, pig: Int, down: Int): Float {
        val total = up + pig + down
        if (total == 0) return 3.0f
        return ((up * 5.0f + pig * 2.5f) / total).coerceIn(0f, 5f)
    }
}
