package dev.inmo.postssystem.features.users.common

import dev.inmo.micro_utils.repos.exposed.AbstractExposedCRUDRepo
import dev.inmo.micro_utils.repos.exposed.initTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.InsertStatement
import org.jetbrains.exposed.sql.statements.UpdateStatement

class ExposedUsersStorage(override val database: Database) : UsersStorage, AbstractExposedCRUDRepo<User, UserId, NewUser>(
    tableName = "Users"
) {
    val userIdColumn = long("userid").autoIncrement()
    val usernameColumn = text("username")
    private val firstNameColumn = text("firstName")
    private val lastNameColumn = text("lastName")

    override val primaryKey: PrimaryKey = PrimaryKey(userIdColumn)

    override val selectByIds: SqlExpressionBuilder.(List<UserId>) -> Op<Boolean> = { userIdColumn.inList(it.map { it.long }) }
    override val selectById: SqlExpressionBuilder.(UserId) -> Op<Boolean> = { userIdColumn.eq(it.long) }
    override val ResultRow.asObject: User
        get() = DefaultUser(
            get(userIdColumn).userId,
            get(firstNameColumn),
            get(lastNameColumn),
            get(usernameColumn).username,
        )

    init {
        initTable()
    }

    override fun insert(value: NewUser, it: InsertStatement<Number>) {
        it[usernameColumn] = value.username.string
        it[firstNameColumn] = value.firstName
        it[lastNameColumn] = value.lastName
    }

    override fun update(id: UserId, value: NewUser, it: UpdateStatement) {
        it[usernameColumn] = value.username.string
        it[firstNameColumn] = value.firstName
        it[lastNameColumn] = value.lastName
    }

    override fun InsertStatement<Number>.asObject(value: NewUser): User = DefaultUser(
        get(userIdColumn).userId,
        get(firstNameColumn),
        get(lastNameColumn),
        get(usernameColumn).username,
    )
}
