import re
import traceback

def easydb_server_start(easydb_context):
    logger = easydb_context.get_logger('base.sso')
    easydb_context.register_callback('sso_get_user', {'callback': 'sso_get_user'})

def sso_get_user(easydb_context, easydb_info):
    logger = easydb_context.get_logger('base.sso')
    try:
        return sso_get_user_record(easydb_context, easydb_info, logger)
    except Exception as e:
        logger.error("exception in SSO module: %s\n%s" % (e, traceback.format_exc()))
        return None

def _format(find_fmt_re, fmt, replacements):
    for match in find_fmt_re.findall(fmt):
        if not match in replacements:
            replacements[match] = ''
    return (fmt % replacements).strip()

def sso_get_user_record(easydb_context, easydb_info, logger):
    user = easydb_context.get_remote_user()
    if not user:
        logger.error('failed to get remote user: %s')
        return None

    replacements = easydb_context.get_environment_variables().copy()

    mapping_conf = easydb_context.get_config('system.sso.environment.mapping')
    if isinstance(mapping_conf, dict):
        for var, conf in mapping_conf.items():
            if not 'attr' in conf:
                raise Exception("expected 'attr' in mapping config for {0}".format(var))
            val = replacements.get(conf['attr'])
            if val:
                vals = [val,]
                input_sep = conf.get('input_separator')
                if input_sep:
                    vals = val.split(input_sep)

                out_vals = []
                if 'regex_match' in conf and 'regex_replace' in conf:
                    re_flags = 0
                    if conf.get('regex_ignore_case'):
                        re_flags |= re.IGNORECASE
                    for val in vals:
                        if conf.get('regex_skip_unmatching'):
                            if not re.match(conf['regex_match'], val, flags = re_flags):
                                continue

                        val = re.sub(conf['regex_match'], conf['regex_replace'], val, flags = re_flags).strip()
                        if len(val):
                            out_vals.append(val)
                else:
                    out_vals = vals

                output_sep = conf.get('output_separator', ',')
                replacements[var] = output_sep.join(out_vals).strip()

    logger.debug(repr(replacements))

    user_conf = easydb_context.get_config('system.sso.environment.user')
    login_format = user_conf.get('login', '%(eppn)s')
    displayname_format = user_conf.get('displayname', '%(displayName)s')
    email_format = user_conf.get('email', None)

    group_conf = easydb_context.get_config('system.sso.environment.groups')
    groups = set()
    if isinstance(group_conf, list):
        for conf in group_conf:
            if not 'attr' in conf:
                raise Exception("expected 'attr' in group config item")
            val = replacements.get(conf['attr'])
            if val:
                divider = conf.get('divider', ';')
                groups.update(val.split(divider))

    find_fmt_re = re.compile('%\(([a-zA-Z0-9_]*)\)s')

    login = _format(find_fmt_re, login_format, replacements)
    if not login:
        logger.error("failed to extract user from environment, format: '%s'" % login_format)
        return None

    emails = []
    if email_format:
        email = _format(find_fmt_re, email_format, replacements)
        if email:
            emails.append({
                'email': email,
                'needs_confirmation': False,
                'use_for_email': True,
                'send_email': True,
                'is_primary': True,
            })

    user_record = {
        'user': {
            'login': login,
            'displayname': _format(find_fmt_re, displayname_format, replacements),
        },
        '_groups': list(groups),
        '_emails': emails
    }

    additional_fields = [
        'address_supplement',
        'company',
        'country',
        'department',
        'first_name',
        'last_name',
        'house_number',
        'phone',
        'postal_code',
        'reference',
        'remarks',
        'street',
        'town',
    ]
    for field in additional_fields:
        fmt = displayname_format = user_conf.get(field, '')
        if fmt is None or fmt == '':
            continue
        user_record['user'][field] = _format(find_fmt_re, fmt, replacements)

    logger.debug(repr(user_record))

    return user_record

# vim:set et:ts=4
