from string import Template

from discord import Guild, Member, User
from discord.ext.commands import Cog

from ..db import Notification, NotificationKind


class Notifications(Cog):
    def __init__(self, scoped_session):
        self._session = scoped_session

    async def _process_event(self, kind: NotificationKind, guild: Guild, user: User):
        db_notif = self._session.query(Notification).get((guild.id, kind))
        if not db_notif:
            return

        channel = guild.get_channel(db_notif.channel_id)
        if not channel:
            return

        template = Template(db_notif.template)
        format_args = {
            "name": user.display_name,
            "fullname": f"{user.name}#{user.discriminator}",
            "mention": user.mention,
            "id": user.id
        }

        await maybe_send(channel, template.safe_substitute(format_args))

    @Cog.listener()
    async def on_member_join(self, member: Member):
        await self._process_event(NotificationKind.JOIN, member.guild, member)

    @Cog.listener()
    async def on_member_remove(self, member: Member):
        # TODO: Maybe don't fire if this is also a ban
        # Potential issue: notifications could be in different channels
        await self._process_event(NotificationKind.LEAVE, member.guild, member)

    @Cog.listener()
    async def on_member_ban(self, guild: Guild, user: User):
        # TODO: Maybe don't fire if ban was by this bot
        # Same potential issues as above
        await self._process_event(NotificationKind.BAN, guild, user)

    @Cog.listener()
    async def on_member_unban(self, guild: Guild, user: User):
        await self._process_event(NotificationKind.UNBAN, guild, user)

@@ -20,16 +20,44 @@
 Template
+%0Afrom typing import Optional
 %0A%0Afrom d
@@ -84,16 +84,29 @@
  Member,
+ TextChannel,
  User%0Afr
@@ -139,16 +139,60 @@
 port Cog
+, Greedy, group, guild_only, has_permissions
 %0A%0Afrom .
@@ -233,16 +233,47 @@
 ionKind%0A
+from ..utils import maybe_send%0A
 %0A%0Aclass 
@@ -1818,24 +1818,1658 @@
 ind.UNBAN, guild, user)%0A
+%0A    @group(aliases=%5B'greetings', 'joins', 'welcome', 'welcomes'%5D)%0A    @guild_only()%0A    @has_permissions(manage_guild=True)%0A    async def notifications(self, ctx):%0A        %22%22%22%0A        Control a server's join/leave/ban notifications.%0A%0A        Required context: Server%0A%0A        Required permissions:%0A            - Manage Server%0A        %22%22%22%0A        if ctx.invoked_subcommand is None:%0A            await maybe_send(ctx, 'Invalid subcommand passed. '%0A                                  'Possible options are %22enable%22, %22move%22, or %22disable%22.')%0A%0A    @notifications.command()%0A    async def move(self, ctx, kinds: Greedy%5BNotificationKind%5D = list(NotificationKind), channel: TextChannel = None):%0A        %22%22%22%0A        Move one or more notification kinds to the specified channel.%0A        Defaults to moving all kinds to the current channel.%0A%0A        Arguments:%0A            - %5Boptional, list%5D kinds: Notification kinds to move.%0A                Not enabled ones are ignored.%0A            - %5Boptional%5D channel: Channel to move notifications to.%0A                Can be specified without specifying any kinds.%0A        %22%22%22%0A        channel = channel or ctx.channel%0A        # Dedupe kinds, but keep list type for SQLA in_ operator%0A        kinds = list(set(kinds))%0A%0A        num_moved = self._session.query(Notification).filter(%0A            Notification.guild_id == ctx.guild.id,%0A            Notification.kind.in_(kinds)%0A        ).update(%7BNotification.channel_id: channel.id%7D, synchronize_session=False)%0A        self._session.commit()%0A%0A        await maybe_send(ctx, f%22Moved %7Bnum_moved%7D notification kind%7B'' if num_moved == 1 else 's'%7D to %7Bchannel.mention%7D.%22)%0A

add move command