/*
 *   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

import de.steamwar.sql.internal.useDb
import org.jetbrains.exposed.v1.core.dao.id.EntityID
import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.dao.IntEntity
import org.jetbrains.exposed.v1.dao.IntEntityClass
import org.jetbrains.exposed.v1.javatime.CurrentTimestamp
import org.jetbrains.exposed.v1.javatime.timestamp
import java.security.MessageDigest
import java.security.SecureRandom
import java.sql.Timestamp
import java.util.*

object TokenTable : IntIdTable("Token") {
    val name = varchar("Name", 64).uniqueIndex()
    val owner = reference("Owner", SteamwarUserTable).index()
    val created = timestamp("Created").defaultExpression(CurrentTimestamp)
    val hash = varchar("Hash", 88).uniqueIndex()
}

class Token(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<Token>(TokenTable) {
        private fun getHash(code: String) =
            Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-512").digest(code.toByteArray()))

        @JvmStatic
        fun createToken(name: String, owner: SteamwarUser): String {
            val random = SecureRandom();
            val bytes = ByteArray(20)
            random.nextBytes(bytes)

            val code = Base64.getEncoder().encodeToString(bytes)

            val hash = getHash(code)

            useDb {
                new {
                    this.name = name
                    this.owner = owner
                    this.hash = hash
                }
            }

            return code
        }

        @JvmStatic
        fun getTokenByCode(code: String) =
            get(getHash(code))

        @JvmStatic
        fun get(hash: String) =
            useDb {
                find { TokenTable.hash eq hash }.firstOrNull()
            }

        @JvmStatic
        fun listUser(user: SteamwarUser) =
            useDb {
                find { TokenTable.owner eq user.id }.toList()
            }
    }

    var name by TokenTable.name
        private set
    var owner by TokenTable.owner.memoizedTransform({ it.id }, { SteamwarUser.byId(it.value)!! })
        private set
    var created by TokenTable.created.transform({ it.toInstant() }, { Timestamp.from(it) })
        private set
    var hash by TokenTable.hash
        private set

    override fun delete() =
        useDb {
            super.delete()
        }
}