import json
import random
import string

class DB:
    def __init__(self, filename):
        self.filename = filename
    def save(self):
        with open(self.filename, 'w') as dbfile:
            json.dump(self._save(), dbfile)

    def restore(self):
        try:
            with open(self.filename, 'r') as dbfile:
                self._restore(json.load(dbfile))
            return True
        except FileNotFoundError:
            #print('"' + self.filename + '" not saved yet; nothing to restore')
            return False

    def refresh(self):
        self.restore()
    def _save(self):
        return {}

    def _restore(self, data):
        pass


class User:
    def __init__(self, username=None, key=None):
        self.username = username
        self.key = key

    def save(self):
        return {
            'username': self.username,
            'key': self.key
        }

    def restore(self, data):
        self.username = data['username']
        self.key = data['key']

    def get_username_key(self):
        return self.username.ljust(24) + ' ' + self.key


class Users(DB):
    def __init__(self):
        super().__init__('users.json')

        self.users = []
        if not self.restore():
            self.save()
    def _save(self):
        out_users = []

        for user in self.users:
            out_users.append(user.save())

        return out_users

    def _restore(self, data):
        self.users = []

        for user_data in data:
            user = User()
            user.restore(user_data)

            self.users.append(user)

    def get_users(self):
        return self.users

    def get_user(self, username):
        self.refresh()

        for user in self.users:
            if user.username == username:
                return user

        return None

    @staticmethod
    def generate_key():
        key_characters = string.ascii_uppercase + string.ascii_lowercase + string.digits
        return ''.join(random.SystemRandom().choice(key_characters) for _ in range(16))

    def add(self, username):
        if self.get_user(username):
            print('attempted to add duplicate user "' + username + '"')
            return None

        user = User(username, Users.generate_key())

        self.users.append(user)

        self.save()

        return user

    def remove(self, username):
        user = self.get_user(username)

        if not user:
            print('attempted to remove user "' + username + '" who does not exist')
            return False

        self.users.remove(user)

        self.save()

        return True

    def rekey(self, username):
        user = self.get_user(username)

        if not user:
            print('attempted to rekey user "' + username + '" who does not exist')
            return False

        user.key = Users.generate_key()

        self.save()

        return True