#!/usr/bin/python3
import os
import argparse
import subprocess
import yaml

parser = argparse.ArgumentParser()
parser.add_argument('--config', type=str, default='/etc/publik/publik.conf')
parser.add_argument('--simulate', action='store_true')
parser.add_argument('--configure', action='store_true')
args = parser.parse_args()

model = """DATABASES['default']['HOST'] = '{host}'
DATABASES['default']['PORT'] = {port}
DATABASES['default']['PASSWORD'] = '{password}'"""


def run_pg(connection, cmd):
    cmd = cmd.replace('"', '\\"')
    if connection.get('host') == 'localhost' and not connection.get('admin'):
        subprocess.call('echo "%s" | sudo -u postgres psql' % cmd, shell=True)
    else:
        admin = connection.get('admin')
        subprocess.call("echo '%s' | psql -h -U %s -W" % (cmd, admin), shell=True)


def main():
    if not os.path.isfile(args.config):
        raise(Exception('Configuration file not found: %s' % args.config))

    with open(args.config) as fh:
        cfg = yaml.load(fh)

        if 'defaults' in cfg.keys():
            defaults = cfg.get('defaults')
        else:
            defaults = {}

        if 'databases' not in defaults.keys() and 'instances' not in cfg.keys():
            raise(Exception('No "instances" nor "defaults" keys found in configuration file'))

    for instance, data in cfg['instances'].items():
        if 'databases' not in data.keys():
            data['databases'] = defaults['databases']

        if 'connection' in defaults.keys():
            connection = defaults['connection']
            if 'connection' in data.keys():
                connection.update(data['connection'])
        else:
            connection = data['connection']


        if args.configure:
            if 'roles' not in data.keys():
                raise(Exception('Not implemented: no passwords defined'))
            configure_briques(connection, data['databases'], data['roles'])
        else:
            if 'roles' not in data.keys():
                print('No "roles" key found, going for passwordless configuration')
                data['roles'] = False
            create_databases(connection, instance, data['databases'], data['roles'])


def configure_briques(connection, databases, roles):
    for database, role in databases.items():

        if database == 'wcs':
            continue

        password = roles[role]
        if database == 'authentic2_multitenant':
            service = 'authentic2-multitenant'
            user = 'authentic-multitenant'
        else:
            user, service = database, database
        settings_d = '/etc/%s/settings.d' % service
        settings = '%s/connection.py' % settings_d

        if not os.path.isdir(settings_d) and not args.simultate:
            os.system('mkdir -p %s' % settings_d)

        s = model.format(database=database, host=connection['host'],
                         port=connection['port'], password=password)

        if args.simulate:
            print(s)
            continue

        with open(settings, 'w') as fh:
            fh.write(s)

        os.system('chown -R %s %s' % (user, settings_d))


def create_databases(connection, instance, databases, roles):
    count = len(databases.keys())
    print('instance {} has {} components'.format(instance, count))

    cmds = []
    for database, role in databases.items():
        if roles:
            password = roles[role]
        else:
            password = False
        cmds.append(gen_cmd(database, role, password))

    if args.simulate:
        print(connection)
        for c in cmds:
            print(c)
    else:
        run_pg(connection, " ".join(cmds))


def gen_cmd(database, role, password):
    out = []
    if password:
        out.append("CREATE USER \"{}\" PASSWORD '{}';".format(role, password))
    else:
        out.append("CREATE USER \"{}\";".format(role))
    out.append("CREATE DATABASE {} WITH OWNER = \"{}\" TEMPLATE = template0 "
               "LC_COLLATE = 'fr_FR.UTF_8' LC_CTYPE = 'fr_FR.UTF-8';".format(database, role))
    if database == 'wcs':
        out.append("ALTER USER wcs CREATEDB;")
    return " ".join(out)


if __name__ == '__main__':
    main()
