/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.sql.internal

import de.steamwar.sql.SteamwarUser
import org.jetbrains.exposed.v1.core.BooleanColumnType
import org.jetbrains.exposed.v1.core.IntegerColumnType
import org.jetbrains.exposed.v1.core.LongColumnType
import org.jetbrains.exposed.v1.core.VarCharColumnType
import org.jetbrains.exposed.v1.jdbc.name
import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager
import java.sql.ResultSet
import java.sql.SQLException

data class Statement(val statement: String) {
    companion object {
        @JvmStatic
        fun closeAll() =
            KotlinDatabase.close()

        @JvmStatic
        fun productionDatabase() =
            TransactionManager.defaultDatabase?.name == "production"
    }

    fun <T> select(user: ResultSetUser<T>, vararg args: Any): T? =
        useDb {
            exec(statement, args = args.map { getArgType(it) }) {
                user.use(it)
            }
        }

    private fun getArgType(obj: Any) =
        when (obj) {
            is String -> VarCharColumnType() to obj
            is Int -> IntegerColumnType() to obj
            is Long -> LongColumnType() to obj
            is Boolean -> BooleanColumnType() to obj
            is SteamwarUser -> IntegerColumnType() to obj.id.value
            else -> error("Unknown type: ${obj::class.simpleName}")
        }

    interface ResultSetUser<T> {
        @Throws(SQLException::class)
        fun use(rs: ResultSet): T?
    }
}