/*
 *   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.IntegerColumnType
import org.jetbrains.exposed.v1.core.and
import org.jetbrains.exposed.v1.core.dao.id.CompositeID
import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
import org.jetbrains.exposed.v1.core.dao.id.EntityID
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.dao.CompositeEntity
import org.jetbrains.exposed.v1.dao.CompositeEntityClass
import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.insertIgnore

object TeamTeilnahmeTable : CompositeIdTable("TeamTeilnahme") {
    val teamId = reference("teamId", TeamTable).index()
    val eventId = reference("eventId", EventTable).index()
    val placement = integer("Placement").nullable()

    override val primaryKey = PrimaryKey(teamId, eventId)

    init {
        addIdColumn(teamId)
        addIdColumn(eventId)
    }
}

class TeamTeilnahme(id: EntityID<CompositeID>) : CompositeEntity(id) {
    companion object : CompositeEntityClass<TeamTeilnahme>(TeamTeilnahmeTable) {
        @JvmStatic
        fun nimmtTeil(teamId: Int, eventId: Int) =
            useDb {
                find { (TeamTeilnahmeTable.teamId eq teamId) and (TeamTeilnahmeTable.eventId eq eventId) }.firstOrNull() != null
            }

        @JvmStatic
        fun teilnehmen(teamId: Int, eventId: Int) =
            useDb {
                TeamTeilnahmeTable.insertIgnore {
                    it[TeamTeilnahmeTable.teamId] = teamId
                    it[TeamTeilnahmeTable.eventId] = eventId
                }
            }

        @JvmStatic
        fun notTeilnehmen(teamId: Int, eventId: Int) =
            useDb {
                TeamTeilnahmeTable.deleteWhere { (TeamTeilnahmeTable.teamId eq teamId) and (TeamTeilnahmeTable.eventId eq eventId) }
            }

        @JvmStatic
        fun deleteFuture(teamId: Int) =
            useDb {
                exec(
                    "DELETE t FROM TeamTeilnahme t INNER JOIN Event e ON t.EventID = e.EventID WHERE t.TeamID = ? AND e.Start > NOW()",
                    args = listOf(IntegerColumnType() to teamId)
                )
            }

        @JvmStatic
        fun getTeams(eventId: Int) =
            useDb {
                find { TeamTeilnahmeTable.eventId eq eventId }.map { Team.byId(it.teamId.value) }.toSet()
            }

        @JvmStatic
        fun getEvents(teamId: Int) =
            useDb {
                find { TeamTeilnahmeTable.teamId eq teamId }.map { Event.byId(it.eventId.value) }.toSet()
            }

        @JvmStatic
        fun getPlacement(team: Team, event: Event) =
            useDb {
                get(CompositeID {
                    it[TeamTeilnahmeTable.teamId] = team.id
                    it[TeamTeilnahmeTable.eventId] = event.id
                }).placement
            }
    }

    val teamId by TeamTeilnahmeTable.teamId
    val eventId by TeamTeilnahmeTable.eventId
    var placement by TeamTeilnahmeTable.placement
}