import sqlalchemy
import sqlalchemy.orm

import cassiopeia.type.dto.common
import cassiopeia.type.core.common

@cassiopeia.type.core.common.inheritdocs
class Participant(cassiopeia.type.dto.common.CassiopeiaDto):
    """
    bot              bool    flag indicating whether or not this participant is a bot
    championId       int     the ID of the champion played by this participant
    profileIconId    int     the ID of the profile icon used by this participant
    spell1Id         int     the ID of the first summoner spell used by this participant
    spell2Id         int     the ID of the second summoner spell used by this participant
    summonerName     str     the summoner name of this participant
    teamId           int     the team ID of this participant, indicating the participant's team
    encryptionKey    str     key used to decrypt the spectator grid game data for playback
    championId       int     the ID of the banned champion
    pickTurn         int     the turn during which the champion was banned
    teamId           int     the ID of the team that banned the champion
    """
    def __init__(self, dictionary):
        self.bot = dictionary.get("bot", False)
        self.championId = dictionary.get("championId", 0)
        self.profileIconId = dictionary.get("profileIconId", 0)
        self.spell1Id = dictionary.get("spell1Id", 0)
        self.spell2Id = dictionary.get("spell2Id", 0)
        self.summonerName = dictionary.get("summonerName", "")
        self.teamId = dictionary.get("teamId", 0)


@cassiopeia.type.core.common.inheritdocs
class Observer(cassiopeia.type.dto.common.CassiopeiaDto):
    """
    encryptionKey    str    key used to decrypt the spectator grid game data for playback
    """
    def __init__(self, dictionary):
        self.encryptionKey = dictionary.get("encryptionKey", "")


@cassiopeia.type.core.common.inheritdocs
class BannedChampion(cassiopeia.type.dto.common.CassiopeiaDto):
    """
    championId    int    the ID of the banned champion
    pickTurn      int    the turn during which the champion was banned
    teamId        int    the ID of the team that banned the champion
    """
    def __init__(self, dictionary):
        self.championId = dictionary.get("championId", 0)
        self.pickTurn = dictionary.get("pickTurn", 0)
        self.teamId = dictionary.get("teamId", 0)


@cassiopeia.type.core.common.inheritdocs
class FeaturedGameInfo(cassiopeia.type.dto.common.CassiopeiaDto):
    """
    bannedChampions      list<BannedChampion>    banned champion information
    gameId               int                     the ID of the game
    gameLength           int                     the amount of time in seconds that has passed since the game started
    gameMode             str                     the game mode (Legal values: CLASSIC, ODIN, ARAM, TUTORIAL, ONEFORALL, ASCENSION, FIRSTBLOOD, KINGPORO)
    gameQueueConfigId    int                     the queue type (queue types are documented on the Game Constants page)
    gameStartTime        int                     the game start time represented in epoch milliseconds
    gameType             str                     the game type (Legal values: CUSTOM_GAME, MATCHED_GAME, TUTORIAL_GAME)
    mapId                int                     the ID of the map
    observers            Observer                the observer information
    participants         list<Participant>       the participant information
    platformId           str                     the ID of the platform on which the game is being played
    """
    def __init__(self, dictionary):
        self.bannedChampions = [(BannedChampion(ban) if not isinstance(ban, BannedChampion) else ban) for ban in dictionary.get("bannedChampions", []) if ban]
        self.gameId = dictionary.get("gameId", 0)
        self.gameLength = dictionary.get("gameLength", 0)
        self.gameMode = dictionary.get("gameMode", "")
        self.gameQueueConfigId = dictionary.get("gameQueueConfigId", 0)
        self.gameStartTime = dictionary.get("gameStartTime", 0)
        self.gameType = dictionary.get("gameType", "")
        self.mapId = dictionary.get("mapId", 0)
        val = dictionary.get("observers", None)
        self.observers = Observer(val) if val and not isinstance(val, Observer) else val
        self.participants = [(Participant(participant) if not isinstance(participant, BannedChampion) else participant) for participant in dictionary.get("participants", []) if participant]
        self.platformId = dictionary.get("platformId", "")

    @property
    def champion_ids(self):
        """Gets all champion IDs contained in this object"""
        ids = set()
        for ban in self.bannedChampions:
            ids.add(ban.championId)
        for p in self.participants:
            ids.add(p.championId)
        return ids

    @property
    def summoner_spell_ids(self):
        """Gets all summoner spell IDs contained in this object"""
        ids = set()
        for p in self.participants:
            if(p.spell1Id):
                ids.add(p.spell1Id)
            if(p.spell2Id):
                ids.add(p.spell2Id)
        return ids


@cassiopeia.type.core.common.inheritdocs
class FeaturedGames(cassiopeia.type.dto.common.CassiopeiaDto):
    """
    clientRefreshInterval    int                       the suggested interval to wait before requesting FeaturedGames again
    gameList                 list<FeaturedGameInfo>    the list of featured games
    """
    def __init__(self, dictionary):
        self.clientRefreshInterval = dictionary.get("clientRefreshInterval", 0)
        self.gameList = [(FeaturedGameInfo(game) if not isinstance(game, FeaturedGameInfo) else game) for game in dictionary.get("gameList", []) if game]

    @property
    def champion_ids(self):
        """Gets all champion IDs contained in this object"""
        ids = set()
        for game in self.gameList:
            ids |= game.champion_ids
        return ids

    @property
    def summoner_spell_ids(self):
        """Gets all summoner spell IDs contained in this object"""
        ids = set()
        for game in self.gameList:
            ids |= game.summoner_spell_ids
        return ids

###############################
# Dynamic SQLAlchemy bindings #
###############################

def _sa_bind_participant():
    global Participant
    @cassiopeia.type.core.common.inheritdocs
    class Participant(Participant, cassiopeia.type.dto.common.BaseDB):
        __tablename__ = "FeaturedGameParticipant"
        bot = sqlalchemy.Column(sqlalchemy.Boolean)
        championId = sqlalchemy.Column(sqlalchemy.Integer)
        profileIconId = sqlalchemy.Column(sqlalchemy.Integer)
        spell1Id = sqlalchemy.Column(sqlalchemy.Integer)
        spell2Id = sqlalchemy.Column(sqlalchemy.Integer)
        summonerName = sqlalchemy.Column(sqlalchemy.String(30))
        teamId = sqlalchemy.Column(sqlalchemy.Integer)
        _id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
        _game_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("FeaturedGameInfo.gameId", ondelete="CASCADE"))

def _sa_bind_observer():
    global Observer
    @cassiopeia.type.core.common.inheritdocs
    class Observer(Observer, cassiopeia.type.dto.common.BaseDB):
        __tablename__ = "FeaturedGameObserver"
        encryptionKey = sqlalchemy.Column(sqlalchemy.String(50))
        _id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
        _game_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("FeaturedGameInfo.gameId", ondelete="CASCADE"))

def _sa_bind_banned_champion():
    global BannedChampion
    @cassiopeia.type.core.common.inheritdocs
    class BannedChampion(BannedChampion, cassiopeia.type.dto.common.BaseDB):
        __tablename__ = "FeaturedGameBannedChampion"
        championId = sqlalchemy.Column(sqlalchemy.Integer)
        pickTurn = sqlalchemy.Column(sqlalchemy.Integer)
        teamId = sqlalchemy.Column(sqlalchemy.Integer)
        _id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
        _game_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("FeaturedGameInfo.gameId", ondelete="CASCADE"))

def _sa_bind_featured_game_info():
    global FeaturedGameInfo
    @cassiopeia.type.core.common.inheritdocs
    class FeaturedGameInfo(FeaturedGameInfo, cassiopeia.type.dto.common.BaseDB):
        __tablename__ = "FeaturedGameInfo"
        bannedChampions = sqlalchemy.orm.relationship("cassiopeia.type.dto.featuredgames.BannedChampion", cascade="all, delete-orphan", passive_deletes=True)
        gameId = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
        gameLength = sqlalchemy.Column(sqlalchemy.Integer)
        gameMode = sqlalchemy.Column(sqlalchemy.String(30))
        gameQueueConfigId = sqlalchemy.Column(sqlalchemy.Integer)
        gameStartTime = sqlalchemy.Column(sqlalchemy.BigInteger)
        gameType = sqlalchemy.Column(sqlalchemy.String(30))
        mapId = sqlalchemy.Column(sqlalchemy.Integer)
        observers = sqlalchemy.orm.relationship("cassiopeia.type.dto.featuredgames.Observer", uselist=False, cascade="all, delete-orphan", passive_deletes=True)
        participants = sqlalchemy.orm.relationship("cassiopeia.type.dto.featuredgames.Participant", cascade="all, delete-orphan", passive_deletes=True)
        platformId = sqlalchemy.Column(sqlalchemy.String(30))

def _sa_bind_all():
    _sa_bind_participant()
    _sa_bind_observer()
    _sa_bind_banned_champion()
    _sa_bind_featured_game_info()