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

import dev.inmo.micro_utils.pagination.*
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.files.common.*
import dev.inmo.postssystem.features.files.common.storage.FilesStorage
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

class BinaryServerContentStorage(
    private val filesStorage: FilesStorage
) : ServerContentStorage<BinaryContent> {
    private val FileId.asContentId
        get() = ContentId(string)
    private val ContentId.asFileId
        get() = FileId(string)
    private val FullFileInfoStorageWrapper.asRegisteredContent
        get() = RegisteredContent(
            id.asContentId,
            BinaryContent(
                fileInfo.name,
                fileInfo.mimeType,
                fileInfo.inputProvider
            )
        )
    private val BinaryContent.asFullFileInfo
        get() = FullFileInfo(
            filename,
            mimeType,
            inputProvider
        )
    override val deletedObjectsIdsFlow: Flow<ContentId> = filesStorage.deletedObjectsIdsFlow.map { it.asContentId }
    override val newObjectsFlow: Flow<RegisteredContent> = filesStorage.newObjectsFlow.map { it.asRegisteredContent }
    override val updatedObjectsFlow: Flow<RegisteredContent> = filesStorage.updatedObjectsFlow.map { it.asRegisteredContent }

    override suspend fun create(values: List<BinaryContent>): List<RegisteredContent> {
        return filesStorage.create(
            values.map { it.asFullFileInfo }
        ).map { it.asRegisteredContent }
    }

    override suspend fun deleteById(ids: List<ContentId>) {
        filesStorage.deleteById(ids.map { it.asFileId })
    }

    override suspend fun update(id: ContentId, value: BinaryContent): RegisteredContent? {
        return filesStorage.update(
            id.asFileId,
            value.asFullFileInfo
        ) ?.asRegisteredContent
    }

    override suspend fun update(values: List<UpdatedValuePair<ContentId, BinaryContent>>): List<RegisteredContent> {
        return filesStorage.update(
            values.map { (id, content) ->
                id.asFileId to content.asFullFileInfo
            }
        ).map {
            it.asRegisteredContent
        }
    }

    override suspend fun contains(id: ContentId): Boolean {
        return filesStorage.contains(id.asFileId)
    }

    override suspend fun count(): Long = filesStorage.count()

    override suspend fun getById(id: ContentId): RegisteredContent? {
        return filesStorage.getFullFileInfo(id.asFileId) ?.asRegisteredContent
    }

    override suspend fun getByPagination(pagination: Pagination): PaginationResult<RegisteredContent> {
        return filesStorage.getByPagination(pagination).let {
            it.changeResultsUnchecked(
                it.results.mapNotNull {
                    filesStorage.getFullFileInfo(it.id) ?.asRegisteredContent
                }
            )
        }
    }
}
