package dev.inmo.postssystem.features.content.server

import dev.inmo.micro_utils.repos.UpdatedValuePair
import dev.inmo.postssystem.features.content.common.*
import dev.inmo.postssystem.features.content.server.storage.ServerContentStorage
import dev.inmo.postssystem.features.content.server.storage.ServerReadContentStorage
import kotlinx.coroutines.flow.Flow
import kotlin.reflect.KClass

class ServerContentStorageWrapper<T: Content>(
    private val originalStorage: ServerContentStorage<T>,
    private val klass: KClass<T>
): ServerContentStorage<Content>, ServerReadContentStorage by originalStorage {
    override val deletedObjectsIdsFlow: Flow<ContentId> by originalStorage::deletedObjectsIdsFlow
    override val newObjectsFlow: Flow<RegisteredContent> by originalStorage::newObjectsFlow
    override val updatedObjectsFlow: Flow<RegisteredContent> by originalStorage::updatedObjectsFlow

    fun mayHandle(content: Content) = klass.isInstance(content)
    @Suppress("UNCHECKED_CAST")
    private fun asHandlableContent(content: Content) = if (mayHandle(content)) content as T else null

    override suspend fun create(values: List<Content>): List<RegisteredContent> {
        return originalStorage.create(
            values.mapNotNull {
                asHandlableContent(it)
            }
        )
    }

    override suspend fun deleteById(ids: List<ContentId>) = originalStorage.deleteById(ids)

    override suspend fun update(id: ContentId, value: Content): RegisteredContent? {
        return originalStorage.update(id, asHandlableContent(value) ?: return null)
    }

    override suspend fun update(values: List<UpdatedValuePair<ContentId, Content>>): List<RegisteredContent> {
        return originalStorage.update(
            values.mapNotNull { (id, content) ->
                id to (asHandlableContent(content) ?: return@mapNotNull null)
            }
        )
    }

}

inline fun <reified T: Content> ServerContentStorage<T>.wrap() = ServerContentStorageWrapper(
    this,
    T::class
)
