package com.pixelized.desktop.lwa.repository.tag

import com.pixelized.desktop.lwa.network.LwaClient
import com.pixelized.shared.lwa.model.tag.Tag
import com.pixelized.shared.lwa.model.tag.TagJson
import com.pixelized.shared.lwa.model.tag.TagJsonFactory
import com.pixelized.shared.lwa.protocol.rest.APIResponse
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

class TagStore(
    private val factory: TagJsonFactory,
    private val client: LwaClient,
) {
    private val characterTagsFlow = MutableStateFlow<Map<String, Tag>>(emptyMap())
    private val alterationTagsFlow = MutableStateFlow<Map<String, Tag>>(emptyMap())
    private val itemTagsFlow = MutableStateFlow<Map<String, Tag>>(emptyMap())
    private val mapTagsFlow = MutableStateFlow<Map<String, Tag>>(emptyMap())

    fun charactersTagFlow(): StateFlow<Map<String, Tag>> = characterTagsFlow

    fun characters(): Collection<Tag> {
        return characterTagsFlow.value.values
    }

    fun character(tagId: String): Tag? {
        return characterTagsFlow.value[tagId]
    }

    fun alterationsTagFlow(): StateFlow<Map<String, Tag>> = alterationTagsFlow

    fun alterations(): Collection<Tag> {
        return alterationTagsFlow.value.values
    }

    fun alteration(tagId: String): Tag? {
        return alterationTagsFlow.value[tagId]
    }

    fun itemsTagFlow(): StateFlow<Map<String, Tag>> = itemTagsFlow

    fun items(): Collection<Tag> {
        return itemTagsFlow.value.values
    }

    fun item(tagId: String): Tag? {
        return itemTagsFlow.value[tagId]
    }

    suspend fun updateCharacterTagsFlow() {
        characterTagsFlow.value = try {
            requestTag { client.getCharacterTags() }
        } catch (exception: Exception) {
            println(exception.message) // TODO proper exception handling
            emptyMap()
        }
    }

    suspend fun updateAlterationTagsFlow() {
        alterationTagsFlow.value = try {
            requestTag { client.getAlterationTags() }
        } catch (exception: Exception) {
            println(exception.message) // TODO proper exception handling
            emptyMap()
        }
    }

    suspend fun updateItemTagsFlow() {
        itemTagsFlow.value = try {
            requestTag { client.getItemTags() }
        } catch (exception: Exception) {
            println(exception.message) // TODO proper exception handling
            emptyMap()
        }
    }

    @Throws
    private suspend inline fun requestTag(
        crossinline block: suspend () -> APIResponse<List<TagJson>>,
    ): Map<String, Tag> {
        val request = block()
        return when (request.success) {
            true -> request.data
                ?.map { factory.convertFromJson(json = it) }
                ?.associateBy { it.id }
                ?: emptyMap()

            else -> LwaClient.error(error = request)
        }
    }
}