package theorycrafter.tournaments

import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import eve.data.EveData
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import theorycrafter.fits.FitHandle
import theorycrafter.TheorycrafterContext
import theorycrafter.tournaments.impl.CharityCup
import theorycrafter.tournaments.impl.ag.AngerGames6
import theorycrafter.tournaments.impl.ag.AngerGames7
import theorycrafter.tournaments.impl.at.AllianceTournamentXX
import theorycrafter.tournaments.impl.at.AllianceTournamentXXI
import java.io.File


/**
 * The tournament descriptors, mapped by the tournament id.
 */
val TournamentDescriptorById: Map<String, TournamentDescriptor> = listOf(
    AngerGames6,
    AllianceTournamentXX,
    CharityCup,
    AllianceTournamentXXI,
    AngerGames7
).associateBy { it.id }


/**
 * Responsible for tournament-related parts of [TheorycrafterContext].
 */
class TournamentContext(


    /**
     * The context [EveData].
     */
    val eveData: EveData,


    /**
     * The directory where tournament repositories are stored.
     */
    private val tournamentsDirectory: File


) {


    /**
     * [Deferred]s loading the tournament, mapped by tournament id.
     */
    private val tournamentDeferredById = mutableMapOf<String, Deferred<Tournament>>()


    /**
     * Returns the [Tournament] with the given descriptor, loading it as needed.
     */
    suspend fun loadTournament(descriptor: TournamentDescriptor): Tournament {
        val deferred = tournamentDeferredById[descriptor.id] ?: coroutineScope {
            async {
                val repository = TournamentRepository.create(descriptor, tournamentsDirectory)
                Tournament(eveData, descriptor, repository)
            }
        }

        return deferred.await()
    }


    /**
     * The descriptor of the active tournament, backed by Compose State.
     */
    val activeTournamentDescriptor: TournamentDescriptor?
        get() = TheorycrafterContext.settings.activeTournamentId?.let {
            TournamentDescriptorById[it]
        }


    /**
     * The rules of the active tournament, backed by Compose State.
     */
    val activeRules: TournamentRules? by derivedStateOf {
        activeTournamentDescriptor?.rulesFactory?.invoke(eveData)
    }


    /**
     * Invoked when some fits have been deleted.
     */
    suspend fun onFitsDeleted(deletedFits: Collection<FitHandle>) {
        // Clear the ship fit ids that have been deleted
        val deletedFitIds = deletedFits.mapTo(mutableSetOf()) { it.fitId }
        for (deferredTournament in tournamentDeferredById.values) {
            val tournament = deferredTournament.await()
            for (comp in tournament.compositions) {
                for (ship in comp.ships) {
                    if ((ship != null) && (ship.fitId in deletedFitIds)){
                        ship.fitId = null
                    }
                }
            }
        }
    }


}


/**
 * The currently ongoing tournament.
 */
@Suppress("RedundantNullableReturnType", "RedundantSuppression")
val CurrentTournamentDescriptor: TournamentDescriptor? = AngerGames7


/**
 * Toggles using the given tournament as the active one.
 */
fun toggleUseCurrentTournamentRules() {
    val tournament = CurrentTournamentDescriptor ?: return
    val activeTournamentId = TheorycrafterContext.settings.activeTournamentId
    TheorycrafterContext.settings.activeTournamentId =
        if (activeTournamentId == tournament.id)
            null
        else
            tournament.id
}
