"""lg-rez / features / Commandes informatives

Commandes donnant aux joueurs des informations sur le jeu, leurs actions, les joueurs en vie et morts...

"""

import traceback
import unidecode

from discord.ext import commands

from lgrez.blocs import bdd_tools, tools
from lgrez.blocs.bdd import session, Joueurs, Roles, Actions, BaseActions


class Informations(commands.Cog):
    """Informations - Commandes disponibles pour en savoir plus sur soi et les autres"""

    @commands.command(aliases=["role", "rôles", "rôle", "camp", "camps"])
    async def roles(self, ctx, *, filtre=None):
        """Affiche la liste des rôles / des informations sur un rôle

        Args:
            filtre: peut être

                - Villageois, Loups, Nécros, Autres pour les rôles d'un camp ;
                - Un nom de rôle pour les informations sur ce rôle.

        Si ``filtre`` n'est pas précisé, liste tous les rôles existants.
        """
        if filtre:
            filtre = tools.remove_accents(filtre.lower())

        if not filtre:
            roles = Roles.query.order_by(Roles.nom).all()
        elif filtre.startswith("villag"):
            roles = Roles.query.filter_by(camp="village").all()
        elif filtre.startswith("loup"):
            roles = Roles.query.filter_by(camp="loups").all()
        elif filtre.startswith("necro"):
            roles = Roles.query.filter_by(camp="nécro").all()
        elif filtre.startswith("autre") or filtre.startswith("solitaire"):
            roles = Roles.query.filter_by(camp="solitaire").all()
        elif filtre:
            if role := Roles.query.get(filtre):     # Slug du rôle trouvé direct
                pass
            else:                                   # Sinon, on cherche en base
                roles = bdd_tools.find_nearest(filtre, Roles, carac="nom")
                if roles:
                    role = roles[0][0]
                else:
                    await ctx.send(f"Rôle / camp \"{filtre}\" non trouvé.")
                    return
            await ctx.send(tools.code_bloc(f"{role.prefixe}{role.nom} – {role.description_courte} (camp : {role.camp})\n\n{role.description_longue}"))
            return

        await tools.send_blocs(ctx,
            f"Rôles trouvés :\n"
            + "\n".join([str(tools.emoji_camp(ctx, role.camp)) + tools.code(f"{role.nom.ljust(25)} {role.description_courte}") for role in roles if not role.nom.startswith("(")])
            + "\n" + tools.ital(f"({tools.code('!roles <role>')} pour plus d'informations sur un rôle.)")
        )


    @commands.command()
    @tools.vivants_only
    @tools.private
    async def menu(self, ctx):
        """Affiche des informations et boutons sur les votes / actions en cours

        Le menu a une place beaucoup moins importante ici que sur Messenger, vu que tout est accessible par commandes.
        """
        member = ctx.author
        joueur = Joueurs.query.get(member.id)
        assert joueur, f"!menu : joueur {member} introuvable"

        reacts = []
        r = "––– MENU –––\n\n"

        if joueur.vote_condamne_:
            r += f" - {tools.emoji(ctx, 'bucher')}  Vote pour le bûcher en cours – vote actuel : {tools.code(joueur.vote_condamne_)}\n"
            reacts.append(tools.emoji(ctx, 'bucher'))
        if joueur.vote_maire_:
            r += f" - {tools.emoji(ctx, 'maire')}  Vote pour le maire en cours – vote actuel : {tools.code(joueur.vote_maire_)}\n"
            reacts.append(tools.emoji(ctx, 'maire'))
        if joueur.vote_loups_:
            r += f" - {tools.emoji(ctx, 'lune')}  Vote des loups en cours – vote actuel : {tools.code(joueur.vote_loups_)}\n"
            reacts.append(tools.emoji(ctx, 'lune'))

        if not reacts:
            r += "Aucun vote en cours.\n"

        actions = Actions.query.filter_by(player_id=member.id).filter(Actions.decision_ != None).all()
        if actions:
            for action in actions:
                r += f" - {tools.emoji(ctx, 'action')}  Action en cours : {tools.code(action.action)} (id {action.id}) – décision : {tools.code(action.decision_)}\n"
            reacts.append(tools.emoji(ctx, 'action'))
        else:
            r += "Aucune action en cours.\n"

        message = await ctx.send(r + f"\n{tools.code('!infos')} pour voir ton rôle et tes actions, {tools.code('@MJ')} en cas de problème")
        for react in reacts:
            await message.add_reaction(react)


    @commands.command()
    @tools.vivants_only
    @tools.private
    async def infos(self, ctx):
        """Affiche tes informations de rôle / actions

        Toutes les actions liées à ton rôle (et parfois d'autres) sont indiquées, même celles que tu ne peux pas utiliser pour l'instant (plus de charges, déclenchées automatiquement...)
        """
        def disponible(action):
            """Renvoie une description human readible des conditions de déclenchement d'<action>"""
            if action.trigger_debut == "temporel":
                dispo = f"De {tools.time_to_heure(action.heure_debut)} à {tools.time_to_heure(action.heure_fin)}"
            elif action.trigger_debut == "perma":
                dispo = f"N'importe quand"
            elif action.trigger_debut == "start":
                dispo = f"Au lancement de la partie"
            elif action.trigger_debut == "mort":
                dispo = f"S'active à ta mort"
            elif action.trigger_debut == "mot_mjs":
                dispo = f"S'active à l'annonce des résultats du vote"
            elif "_" in action.trigger_debut:
                quoi, qui = action.trigger_debut.split("_")
                d_quoi = {"open": "l'ouverture",
                          "close": "la fermeture",
                          "remind": "personne utilise ça",
                }
                d_qui = {"cond": "du vote condamné",
                         "maire": "du vote pour la mairie",
                         "loups": "du vote pour les loups",
                         "action": "personne utilise ça",
                }
                try:
                    dispo = f"S'active à {d_quoi[quoi]} {d_qui[qui]}"
                except KeyError:
                    dispo = f"S'active à {quoi}_{qui}"
            else:
                dispo = action.trigger_debut

            return dispo


        member = ctx.author
        joueur = Joueurs.query.get(member.id)
        assert joueur, f"!menu : joueur {member} introuvable"
        r = ""

        r += f"Ton rôle actuel : {tools.bold(tools.nom_role(joueur.role) or joueur.role)}\n"
        r += tools.ital(f"({tools.code(f'!roles {joueur.role}')} pour tout savoir sur ce rôle)")

        actions = Actions.query.filter_by(player_id=member.id).all()

        if actions:
            r += "\n\nActions :"
            r += tools.code_bloc("\n".join([(
                f" - {str(action.action).ljust(20)} "
                + (f"Cooldown : {cooldown}" if (cooldown := action.cooldown) else disponible(action)).ljust(22)
                + (f"   {action.charges} charge(s){' pour cette semaine' if (action.refill and 'weekends' in action.refill) else ''}" if isinstance(action.charges, int) else "Illimitée")     # Vraiment désolé pour cette immondice
                ) for action in actions]
            ))
        else:
            r += "\n\nAucune action disponible."

        await ctx.send(r + f"\n{tools.code('!menu')} pour voir les votes et actions en cours, {tools.code('@MJ')} en cas de problème")



    @commands.command()
    async def vivants(self, ctx):
        """Affiche la liste des joueurs vivants

        Aussi dite : « liste des joueurs qui seront bientôt morts »
        """
        mess = "Les joueurs vivants sont : \n"
        joueurs = [joueur for joueur in Joueurs.query.filter(Joueurs.statut != "mort").order_by(Joueurs.nom)]

        if ctx.bot.config.get("demande_chambre", True):
            for joueur in joueurs:
                mess += f" - {joueur.nom.ljust(15)} en chambre {joueur.chambre}\n"
        else:
            for joueur in joueurs:
                mess += f" - {joueur.nom}\n"

        await tools.send_code_blocs(ctx, mess)


    @commands.command()
    async def morts(self, ctx):
        """Affiche la liste des joueurs morts

        Aussi dite : « liste des joueurs qui mangent leurs morts »
        """
        mess = "Les morts sont :\n"
        joueurs = [joueur.nom for joueur in Joueurs.query.filter_by(statut = "mort").order_by(Joueurs.nom)]
        if not joueurs:
            mess += "Toi (mais tu ne le sais pas encore)"
        else:
            for joueur in joueurs:
                mess += f" - {joueur} \n"
        await tools.send_code_blocs(ctx, mess)
