package dev.inmo.postssystem.features.auth.server.tokens

import dev.inmo.postssystem.features.auth.common.AuthCreds
import dev.inmo.postssystem.features.users.common.*
import dev.inmo.micro_utils.repos.exposed.AbstractExposedReadCRUDRepo
import dev.inmo.micro_utils.repos.exposed.initTable
import org.jetbrains.exposed.sql.*

private class ExposedUsersAuthenticationRepo(
    override val database: Database,
    private val usersRepo: ExposedUsersStorage
) : AbstractExposedReadCRUDRepo<UserId, AuthCreds>("UsersAuthentications") {
    private val passwordColumn = text("password")
    private val userIdColumn = long("userid").uniqueIndex() references usersRepo.userIdColumn

    override val primaryKey: PrimaryKey = PrimaryKey(userIdColumn)

    override val ResultRow.asObject: UserId
        get() = UserId(get(userIdColumn))
    override val selectById: SqlExpressionBuilder.(AuthCreds) -> Op<Boolean> = {
        usersRepo.select {
            usersRepo.usernameColumn.eq(it.username.string)
        }.firstOrNull() ?.get(usersRepo.userIdColumn) ?.let { userId ->
            userIdColumn.eq(userId).and(passwordColumn.eq(it.password))
        } ?: Op.FALSE
    }

    init {
        initTable()
        uniqueIndex("${tableName}_user_password", userIdColumn, passwordColumn)
    }
}

fun exposedUsersAuthenticator(
    database: Database,
    usersRepo: ExposedUsersStorage
): UserAuthenticator {
    val usersAuthenticatorRepo = ExposedUsersAuthenticationRepo(database, usersRepo)
    return UserAuthenticator {
        val userId = usersAuthenticatorRepo.getById(it) ?: return@UserAuthenticator null
        usersRepo.getById(userId)
    }
}

