# Generated by Django 2.2.26 on 2022-07-27 15:04

import json
import logging

from django.core.exceptions import MultipleObjectsReturned
from django.db import migrations, transaction

logger = logging.getLogger('authentic2.auth_saml')


def get_key(obj, name, max_length=None, default=''):
    setting = obj.get(name)

    expected_type = type(default)
    if not isinstance(setting, expected_type):
        setting = None

    if setting is None:
        setting = default

    return setting[:max_length] if max_length else setting


def get_ou(role_desc, ou_model):
    ou_desc = role_desc.get('ou')
    if ou_desc is None:
        return None
    if not isinstance(ou_desc, dict):
        return
    slug = ou_desc.get('slug')
    name = ou_desc.get('name')
    if slug:
        if not isinstance(slug, str):
            return
        try:
            return ou_model.objects.get(slug=slug)
        except ou_model.DoesNotExist:
            return
    elif name:
        if not isinstance(name, str):
            return
        try:
            return ou_model.objects.get(name=name)
        except ou_model.DoesNotExist:
            pass


def get_role(mapping, role_model, ou_model):
    role_desc = mapping.get('role')
    if not role_desc or not isinstance(role_desc, dict):
        return
    slug = role_desc.get('slug')
    name = role_desc.get('name')
    ou = get_ou(role_desc, ou_model)

    kwargs = {}
    if ou:
        kwargs['ou'] = ou

    if slug:
        if not isinstance(slug, str):
            return
        kwargs['slug'] = slug
    elif name:
        if not isinstance(name, str):
            return
        kwargs['name'] = name
    else:
        return

    try:
        return role_model.objects.get(**kwargs)
    except role_model.DoesNotExist:
        pass
    except MultipleObjectsReturned:
        pass


def migrate_jsonfields(apps, schema_editor):
    SAMLAuthenticator = apps.get_model('authentic2_auth_saml', 'SAMLAuthenticator')
    SAMLAttributeLookup = apps.get_model('authentic2_auth_saml', 'SAMLAttributeLookup')
    SetAttributeAction = apps.get_model('authentic2_auth_saml', 'SetAttributeAction')
    AddRoleAction = apps.get_model('authentic2_auth_saml', 'AddRoleAction')
    RenameAttributeAction = apps.get_model('authentic2_auth_saml', 'RenameAttributeAction')
    Role = apps.get_model('a2_rbac', 'Role')
    OU = apps.get_model('a2_rbac', 'OrganizationalUnit')

    def create_related_objects(authenticator):
        for obj in authenticator.lookup_by_attributes:
            saml_attribute = get_key(obj, 'saml_attribute', 1024)
            user_field = get_key(obj, 'user_field', 256)
            if saml_attribute and user_field:
                SAMLAttributeLookup.objects.create(
                    authenticator=authenticator,
                    saml_attribute=saml_attribute,
                    user_field=user_field,
                    ignore_case=get_key(obj, 'ignore-case', default=False),
                )
        for obj in authenticator.a2_attribute_mapping:
            action = obj.get('action') or ''
            action = action.replace('_', '-')
            if not action or action == 'set-attribute':
                attribute = get_key(obj, 'attribute', 256)
                saml_attribute = get_key(obj, 'saml_attribute', 1024)
                if attribute and saml_attribute:
                    SetAttributeAction.objects.create(
                        authenticator=authenticator,
                        attribute=attribute,
                        saml_attribute=saml_attribute,
                        mandatory=get_key(obj, 'mandatory', default=False),
                    )
            elif action == 'rename':
                from_name = get_key(obj, 'from', 1024)
                to_name = get_key(obj, 'to', 64)
                if from_name and to_name:
                    RenameAttributeAction.objects.create(
                        authenticator=authenticator,
                        from_name=from_name,
                        to_name=to_name,
                    )
            elif action in ('toggle-role', 'add-role'):
                role = get_role(obj, Role, OU)
                if role:
                    AddRoleAction.objects.create(
                        authenticator=authenticator,
                        role=role,
                        condition=get_key(obj, 'condition', 256),
                        mandatory=get_key(obj, 'mandatory', default=False),
                    )

    for authenticator in SAMLAuthenticator.objects.all():
        try:
            with transaction.atomic():
                create_related_objects(authenticator)
        except Exception:
            logger.exception('could not create related objects for authenticator %s', authenticator)
            logger.warning(
                'attribute mapping for %s: %s', authenticator, json.dumps(authenticator.a2_attribute_mapping)
            )
            logger.warning(
                'lookup by attributes for %s: %s',
                authenticator,
                json.dumps(authenticator.lookup_by_attributes),
            )


class Migration(migrations.Migration):
    dependencies = [
        (
            'authentic2_auth_saml',
            '0005_addroleaction_renameattributeaction_samlattributelookup_setattributeaction',
        ),
        ('a2_rbac', '0029_use_unique_constraints'),
    ]

    operations = [
        migrations.RunPython(migrate_jsonfields, reverse_code=migrations.RunPython.noop),
    ]
