import copy
import os
import subprocess
from g import config_dir, templates_dir, DEFAULT_GID, DEFAULT_UID, data_dir
from urllib.parse import urlsplit, unquote
from utils.jinja import render_jinja
from utils.misc import prepare_dir

registry_config_dir = os.path.join(config_dir, "registry")
registry_config_template_path = os.path.join(templates_dir, "registry", "config.yml.jinja")
registry_conf = os.path.join(config_dir, "registry", "config.yml")
registry_passwd_path = os.path.join(config_dir, "registry", "passwd")
registry_data_dir = os.path.join(data_dir, 'registry')

levels_map = {
    'debug': 'debug',
    'info': 'info',
    'warning': 'warn',
    'error': 'error',
    'fatal': 'fatal'
}

def prepare_registry(config_dict):
    prepare_dir(registry_data_dir, uid=DEFAULT_UID, gid=DEFAULT_GID)
    prepare_dir(registry_config_dir)

    gen_passwd_file(config_dict)
    storage_provider_info = get_storage_provider_info(
        config_dict['storage_provider_name'],
        config_dict['storage_provider_config'])

    # process redis info
    redis_ops = parse_redis(config_dict['redis_url_reg'])

    render_jinja(
        registry_config_template_path,
        registry_conf,
        uid=DEFAULT_UID,
        gid=DEFAULT_GID,
        level=levels_map[config_dict['log_level']],
        storage_provider_info=storage_provider_info,
        **config_dict, **redis_ops)

def parse_redis(redis_url):
    u = urlsplit(redis_url)
    if not u.scheme or u.scheme == 'redis':
        return {
            'redis_host': u.netloc.split('@')[-1],
            'redis_password': '' if u.password is None else unquote(u.password),
            'redis_db_index_reg': u.path and int(u.path[1:]) or 0,
            'redis_enableTLS': 'false',
        }
    elif u.scheme == 'rediss':
        return {
            'redis_host': u.netloc.split('@')[-1],
            'redis_password': '' if u.password is None else unquote(u.password),
            'redis_db_index_reg': u.path and int(u.path[1:]) or 0,
            'redis_enableTLS': 'true',
        }
    elif u.scheme == 'redis+sentinel':
        return {
            'sentinel_master_set': u.path.split('/')[1],
            'redis_host': u.netloc.split('@')[-1],
            'redis_password': '' if u.password is None else unquote(u.password),
            'redis_db_index_reg': len(u.path.split('/')) == 3 and int(u.path.split('/')[2]) or 0,
            'redis_enableTLS': 'false',
        }
    elif u.scheme == 'rediss+sentinel':
        return {
            'sentinel_master_set': u.path.split('/')[1],
            'redis_host': u.netloc.split('@')[-1],
            'redis_password': '' if u.password is None else unquote(u.password),
            'redis_db_index_reg': len(u.path.split('/')) == 3 and int(u.path.split('/')[2]) or 0,
            'redis_enableTLS': 'true',
        }
    else:
        raise Exception('bad redis url for registry:' + redis_url)

def get_storage_provider_info(provider_name, provider_config):
    provider_config_copy = copy.deepcopy(provider_config)
    if provider_name == "filesystem":
        if not (provider_config_copy and ('rootdirectory' in provider_config_copy)):
            provider_config_copy['rootdirectory'] = '/storage'
    if provider_name == 'gcs' and provider_config_copy.get('keyfile'):
        provider_config_copy['keyfile'] = '/etc/registry/gcs.key'
    # generate storage configuration section in yaml format
    storage_provider_conf_list = [provider_name + ':']
    for config in provider_config_copy.items():
        if config[1] is None:
            value = ''
        elif config[1] == True:
            value = 'true'
        else:
            value = config[1]
        storage_provider_conf_list.append('{}: {}'.format(config[0], value))
    storage_provider_info = ('\n' + ' ' * 4).join(storage_provider_conf_list)
    return storage_provider_info

def gen_passwd_file(config_dict):
    return subprocess.call(["/usr/bin/htpasswd", "-bcB", registry_passwd_path, config_dict['registry_username'],
                            config_dict['registry_password']], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
