package dev.inmo.postssystem.core.content.api.business.content_adapters.binary

import dev.inmo.micro_utils.coroutines.doOutsideOfCoroutine
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.micro_utils.repos.set
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import java.io.File

class FilesStoreRepoAdapter(
    private val filesRepo: KeyValueRepo<String, File>,
    private val temporalFilesFolder: File
) : KeyValueRepo<String, ByteArray> {
    private val File.asByteArray
        get() = readBytes()
    override val onNewValue: Flow<Pair<String, ByteArray>> = filesRepo.onNewValue.map { (filename, file) ->
        filename to file.asByteArray
    }
    override val onValueRemoved: Flow<String> = filesRepo.onValueRemoved

    init {
        temporalFilesFolder.mkdirs()
    }

    override suspend fun contains(key: String): Boolean = filesRepo.contains(key)

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

    override suspend fun get(k: String): ByteArray? = filesRepo.get(k) ?.asByteArray

    override suspend fun keys(
        v: ByteArray,
        pagination: Pagination,
        reversed: Boolean
    ): PaginationResult<String> = emptyPaginationResult()

    override suspend fun keys(
        pagination: Pagination,
        reversed: Boolean
    ): PaginationResult<String> = filesRepo.keys(pagination, reversed)

    override suspend fun set(toSet: Map<String, ByteArray>) {
        supervisorScope {
            toSet.map { (filename, bytes) ->
                launch {
                    safelyWithoutExceptions {
                        val file = File(temporalFilesFolder, filename).also {
                            it.delete()
                            doOutsideOfCoroutine {
                                it.createNewFile()
                                it.writeBytes(bytes)
                            }
                        }
                        filesRepo.set(filename, file)
                        doOutsideOfCoroutine { file.delete() }
                    }
                }
            }
        }.joinAll()
    }

    override suspend fun unset(toUnset: List<String>) = filesRepo.unset(toUnset)

    override suspend fun values(
        pagination: Pagination,
        reversed: Boolean
    ): PaginationResult<ByteArray> = filesRepo.values(pagination, reversed).let {
        PaginationResult(
            it.page,
            it.pagesNumber,
            it.results.map { it.readBytes() },
            it.size
        )
    }

}