package dev.inmo.postssystem.core.exposed.content

import dev.inmo.postssystem.core.content.BinaryContent
import dev.inmo.postssystem.core.content.ContentId
import dev.inmo.micro_utils.mime_types.mimeType
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.api.ExposedBlob
import org.jetbrains.exposed.sql.transactions.transaction

private class BinaryContentHolderRepoTable(
    private val database: Database
) : ContentHolderRepo<BinaryContent>, Table() {
    private val idColumn = text("id")
    private val dataColumn = blob("data")
    private val mimeColumn = text("mimeType")
    private val originalFileNameColumn = text("filename")
    override val primaryKey: PrimaryKey = PrimaryKey(idColumn)

    init {
        transaction (
            db = database
        ) {
            SchemaUtils.createMissingTablesAndColumns(this@BinaryContentHolderRepoTable)
        }
    }

    override suspend fun getContent(id: ContentId): BinaryContent? = transaction (
        db = database
    ) {
        select {
            idColumn.eq(id)
        }.limit(1).firstOrNull() ?.let {
            val bytes = it[dataColumn].bytes
            BinaryContent(
                mimeType(it[mimeColumn]),
                it[originalFileNameColumn]
            ) {
                bytes
            }
        }
    }

    override suspend fun removeContent(id: ContentId) {
        transaction(
            db = database
        ) {
            deleteWhere { idColumn.eq(id) }
        }
    }

    override suspend fun putContent(id: ContentId, content: BinaryContent) {
        transaction(
            db = database
        ) {
            insert {
                it[idColumn] = id
                it[originalFileNameColumn] = content.originalFileName
                it[mimeColumn] = content.mimeType.raw
                it[dataColumn] = ExposedBlob(content.dataAllocator())
            }
        }
    }
}

class BinaryContentHolderRepo(
    database: Database
) : ContentHolderRepo<BinaryContent> by BinaryContentHolderRepoTable(database)