package dev.inmo.postssystem.features.files.common

import dev.inmo.postssystem.features.files.common.storage.ReadFilesStorage
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import io.ktor.utils.io.streams.asInput
import java.io.File

class DiskReadFilesStorage(
    private val filesFolder: File,
    private val metasKeyValueRepo: ReadKeyValueRepo<FileId, MetaFileInfo>
) : ReadFilesStorage {
    private val FileId.file
        get() = File(filesFolder, string)

    init {
        if (!filesFolder.exists()) {
            filesFolder.mkdirs()
        } else {
            require(filesFolder.isDirectory) { "$filesFolder must be a directory" }
        }
    }

    private suspend fun FileId.meta(): MetaFileInfoStorageWrapper? {
        return MetaFileInfoStorageWrapper(
            this,
            metasKeyValueRepo.get(this) ?: return null
        )
    }

    override suspend fun getBytes(id: FileId): ByteArray = id.file.readBytes()

    override suspend fun getFullFileInfo(id: FileId): FullFileInfoStorageWrapper? = getById(
        id
    ) ?.let {
        FullFileInfoStorageWrapper(
            id,
            FullFileInfo(
                it.fileInfo.name,
                it.fileInfo.mimeType
            ) {
                id.file.inputStream().asInput()
            }
        )
    }

    override suspend fun contains(id: FileId): Boolean = metasKeyValueRepo.contains(id)

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

    override suspend fun getById(id: FileId): MetaFileInfoStorageWrapper? = id.meta()

    override suspend fun getByPagination(pagination: Pagination): PaginationResult<MetaFileInfoStorageWrapper> {
        val keys = metasKeyValueRepo.keys(pagination)
        return keys.changeResults(
            keys.results.mapNotNull {
                MetaFileInfoStorageWrapper(
                    it,
                    metasKeyValueRepo.get(it) ?: return@mapNotNull null
                )
            }
        )
    }
}
