#! /usr/bin/python3

from app import app, db
from app.models.users import Member, Group, GroupPrivilege
from app.models.privs import SpecialPrivilege
from app.models.trophies import Trophy, Title, TrophyMember
from app.models.forum import Forum
from app.utils import unicode_names
import os
import sys
import yaml
import readline

help_msg = """
This is the Planète Casio master shell. Type 'exit' or C-D to leave.

Type a category name to see a list of elements. Available categories are:

  'members'          Registered community members
  'groups'           Privilege groups
  'trophies'         Trophies
  'trophy-members'   Trophies owned by members
  'forums'           Forum tree

Type a category name followed by 'clear' to remove all entries in the category.

Type 'create-groups-and-privs' to recreate all groups and privileges to the
default. This function generates a minimal set of groups and members to prepare
the database.
1. Deletes all groups
2. Creates groups 'Administrateur', 'Modérateur', 'Développeur', 'Rédacteur',
   'Responsable Communauté', 'Partenaire', 'Compte communautaire', 'Robot', and
   'Membre de CreativeCalc'
3. Grants privileges related to these groups
4. Recreates common accounts: 'Planète Casio' (community account) and 'GLaDOS'
   (robot)

Type 'add-group <member> #<group-id>' to add a new member to a group.

Type 'create-trophies' to reset trophies and titles.

Type 'create-forums' to reset the forum tree.
"""

#
#  Category viewers
#

def members(*args):
    if args == ("clear",):
        for m in Member.query.all():
            m.delete()
        db.session.commit()
        print("Removed all members.")
        return

    for m in Member.query.all():
        print(m)

def groups(*args):
    if args == ("clear",):
        for g in Group.query.all():
            g.delete()
        db.session.commit()
        print("Removed all groups.")
        return

    for g in Group.query.all():
         print(f"#{g.id}  {g.name}")

def trophies(*args):
    if args == ("clear",):
        for t in Trophy.query.all():
            db.session.delete(t)
        db.session.commit()
        print("Removed all trophies.")
        return

    for t in Trophy.query.all():
        print(t)

def trophy_members(*args):
    for t in Trophy.query.all():
        if t.owners == []:
            continue

        print(t)
        for m in t.owners:
            print(f"  {m}")

def forums(*args):
    if args == ("clear",):
        for f in Forum.query.all():
            db.session.delete(f)
        db.session.commit()
        print("Removed all forums.")
        return

    for f in Forum.query.all():
        parent = f"in {f.parent.url}" if f.parent is not None else "root"
        print(f"{f.url} ({parent}) [{f.prefix}]: {f.name}")
        print(f"  {f.descr}")

#
#  Creation and edition
#

def create_groups_and_privs():
    # Clean up groups
    groups("clear")

    # Create base groups
    gr = []
    with open(os.path.join(app.root_path, "data", "groups.yaml")) as fp:
        gr = yaml.safe_load(fp.read())

    for g in gr:
        g["obj"] = Group(g["name"], g["css"], g["descr"])
        db.session.add(g["obj"])
    db.session.commit()

    for g in gr:
        for priv in g.get("privs", "").split():
            db.session.add(GroupPrivilege(g["obj"], priv))
    db.session.commit()

    print(f"Created {len(gr)} groups.")

    # Clean up test members
    for name in "PlanèteCasio GLaDOS".split():
        m = Member.query.filter_by(name=name).first()
        if m is not None:
            m.delete()

    print("Removed test members.")

    # Create template members

    def addgroup(member, group):
        g = Group.query.filter_by(name=group).first()
        if g is not None:
            member.groups.append(g)

    m = Member("PlanèteCasio", "contact@planet-casio.com", "nologin")
    addgroup(m, "Compte communautaire")
    addgroup(m, "No login")
    db.session.add(m)

    m = Member("GLaDOS", "glados@aperture.science", "nologin")
    m.xp = 1338
    addgroup(m, "Robot")
    addgroup(m, "No login")
    db.session.add(m)
    db.session.commit()

    db.session.add(SpecialPrivilege(m, "edit-posts"))
    db.session.add(SpecialPrivilege(m, "shoutbox-ban"))

    db.session.commit()

    print(f"Created 2 test members with some privileges.")


def create_trophies():
    # Clean up trophies
    trophies("clear")

    # Create base trophies
    tr = []
    with open(os.path.join(app.root_path, "data", "trophies.yaml")) as fp:
        tr = yaml.safe_load(fp.read())

    for t in tr:
        if t["is_title"]:
            trophy = Title(t["name"], t.get("css", ""))
        else:
            trophy = Trophy(t["name"])
        db.session.add(trophy)
    db.session.commit()

    print(f"Created {len(tr)} trophies.")

def create_forums():
    # Clean up forums
    forums("clear")

    # Create the forum tree
    fr = []
    success = 0
    with open(os.path.join(app.root_path, "data", "forums.yaml")) as fp:
        fr = yaml.safe_load(fp.read())

    for url, f in fr.items():
        if url == "/":
            parent = None
        else:
            parent_url = url.rsplit('/', 1)[0]
            if parent_url == "":
                parent_url = "/"
            parent = Forum.query.filter_by(url=parent_url).first()

            if parent is None:
                print(f"error: no parent with url {parent_url} for {url}")
                continue

        f = Forum(url, f['name'], f['prefix'], f.get('descr', ''), parent)
        db.session.add(f)
        success += 1

    db.session.commit()
    print(f"Created {success} forums.")

def add_group(member, group):
    if group[0] != "#":
        print(f"error: group id {group} should start with '#'")
        return
    gid = int(group[1:])

    norm = unicode_names.normalize(member)

    g = Group.query.filter_by(id=gid).first()
    m = Member.query.filter_by(norm=norm).first()

    if m is None:
        print(f"error: no member has a normalized name of '{norm}'")
        return

    m.groups.append(g)
    db.session.add(m)
    db.session.commit()

#
#  Main program
#

print(help_msg)

commands = {
    "exit":                     lambda: sys.exit(0),
    "members":                  members,
    "groups":                   groups,
    "trophies":                 trophies,
    "trophy-members":           trophy_members,
    "forums":                   forums,
    "create-groups-and-privs":  create_groups_and_privs,
    "create-trophies":          create_trophies,
    "create-forums":            create_forums,
    "add-group":                add_group,
}

while True:
    try:
        print("@> ", end="")
        cmd = input().split()
    except EOFError:
        sys.exit(0)

    if not cmd:
        continue
    if cmd[0] not in commands:
        print(f"error: unknown command '{cmd[0]}'")
    else:
        commands[cmd[0]](*cmd[1:])
