#!/usr/bin/env python3

import os
import discord
from discord.ext import commands
from discord import Member


# Discord constants
CLIENT = discord.Client()
TOKEN = os.environ['NAME_TOKEN']
BOT = commands.Bot(command_prefix='.')


# Bot specific globals
games_list = []


class Game:
    def __init__(self, name):
        self.name = name
        self.aliases = {}
        self.active = False

    def create_alias(self, member, alias):
        '''Takes in member and associates it with string alias.'''
        self.aliases[member] = alias

    def remove_alias(self, member):
        self.aliases.pop(member, None)


# Helper functions
def clear_active():
    for game in games_list:
        game.active = False


def save_games():
    with open('saved_games', 'w+') as f:
        for game in games_list:
            f.write('start ' + game.name + '\n')
            for member in game.aliases:
                # Use a hash character as a separator because it is not allowed
                # in Discord usernames
                f.write(member.name + '#' + game.aliases[member] + '\n')


@BOT.event
async def on_ready():
    global games_list
    members = BOT.guilds[0].members
    try:
        with open('saved_games', 'r') as f:
            for line in f:
                if line[:5] == 'start':
                    name = line[6:-1]
                    print(name)
                    new_game = Game(name)
                    clear_active()
                    new_game.active = True
                    games_list.append(new_game)
                else:
                    idx = line.index('#')
                    member_name = line[:idx]
                    nickname = line[idx+1:-1]
                    member = discord.utils.get(members, name=member_name)
                    game = discord.utils.get(games_list, active=True)
                    game.create_alias(member, nickname)
        clear_active()
    except IOError:
        print('Save file not found')


# Discord commands
@BOT.command()
async def create(ctx, name):
    '''Create a new Game and list of aliases'''
    new_game = Game(name)
    clear_active()
    new_game.active = True
    games_list.append(new_game)
    save_games()
    msg = f'''New game "{new_game.name}" was created.
    Add some nicknames with the .add command.'''
    await ctx.send(msg)


@BOT.command()
async def games(ctx):
    msg = '__Games:__\n'
    for game in games_list:
        msg += f'+ {game.name}: {len(game.aliases)} nicknames'
        if game.active:
            msg += ' [ACTIVE]'
        msg += '\n'
    await ctx.send(msg)


@BOT.command()
async def switch(ctx, other):
    global games_list
    clear_active()
    for game in games_list:
        if game.name == other:
            game.active = True
            # Update
            for member in game.aliases:
                await member.edit(nick=game.aliases[member])
            await ctx.send(f'Switched to Game: __{game.name}__')
            return
    await ctx.send('Game not found')


@BOT.command()
async def add(ctx, member: Member, nickname):
    global games_list
    for game in games_list:
        if game.active:
            game.create_alias(member, nickname)
            save_games()
            await member.edit(nick=game.aliases[member])
            await ctx.send(f'**{game.name}**: @{member.name[:8]}... ~> '
                           f'{game.aliases[member]}')


@BOT.command()
async def names(ctx):
    msg = '__Nicknames__\n'
    for game in games_list:
        if game.active:
            for member in game.aliases:
                msg += '@' + member.name[:8] + '... ~> ' + game.aliases[member]
                msg += '\n'
    await ctx.send(msg)


if __name__ == '__main__':
    BOT.run(TOKEN)
