import sys
import loader

from django.db.transaction import atomic

from authentic2.custom_user.models import User
from authentic2.a2_rbac.models import OrganizationalUnit as OU
from django.contrib.contenttypes.models import ContentType
from authentic2.models import UserExternalId, Attribute, AttributeValue

user_ct = ContentType.objects.get_for_model(User)
            
user_attributes_mapping = {
    'Prenom': 'first_name',
    'Nom': 'last_name',
    'Nom_JF': 'nom_de_naissance',
    'Civilite': 'title',
    'birthdate': 'birthdate',
    'Lieu_Naissance': 'lieu_de_naissance',
    'tel_mobile': 'mobile',
    'tel_fixe': 'phone',
    'NO_Voie': 'address',
    'Batiment_Residence': 'complement_d_adresse',
    'CP': 'zipcode',
    'Ville': 'city',
}

attributes = {attribute.name: attribute for attribute in Attribute.objects.filter(name__in=user_attributes_mapping.values())}
assert set(attributes.keys()) == set(user_attributes_mapping.values())

logger = loader.logger

keys, data = loader.load(sys.argv[1])

logger.handlers[0].level = logging.INFO

with atomic():
    senior_ou, created = OU.objects.update_or_create(slug='senior', defaults={'name': 'Sénior'})

    guids = {row['guid']: row for row in data}

    user_by_guid = {user.uuid: user for user in User.objects.filter(uuid__in=guids.keys())}


    to_bulk_create = []
    to_save = []

    logger.info('Creating users...')
    for i, row in enumerate(data):
        guid = row['guid']
        
        user = user_by_guid.get(guid, User(uuid=guid))

        save = not bool(user.pk)

        defaults = {
            'ou': senior_ou,
            'first_name': row['Prenom'],
            'last_name': row['Nom'],
            'email': row['email'] or '',
            'email_verified': bool(row['Email']),
        }
        for key, value in defaults.items():
            if getattr(user, key) != value:
                setattr(user, key, value)
                save = True

        if save:
            if user.pk:
                to_save.append(user)
            else:
                to_bulk_create.append(user)

    User.objects.bulk_create(to_bulk_create)
    for user in to_save:
        user.save()

    user_by_guid = {user.uuid: user for user in User.objects.filter(uuid__in=guids.keys())}

    user_ids = set(user.pk for user in user_by_guid.values())

    external_id_by_user = {uei.user_id: uei for uei in UserExternalId.objects.filter(user_id__in=user_ids)}

    logger.info('Created %s users...', len(to_bulk_create))
    logger.info('Updated %s users...', len(to_save))

    logger.info('Creating UserExternalId...')
    to_bulk_create = []
    to_save = []
    for user in user_by_guid.values():
        ppid = guids[user.uuid]['ppid']
        uei = external_id_by_user.get(user.pk, UserExternalId(user=user, source='eudonet'))
        save = not bool(uei.pk)
        if uei.source != 'eudonet':
            uei.source = 'eudonet'
            save = True
        if uei.external_id != ppid:
            uei.external_id = ppid
            save = True

        if save:
            if uei.pk:
                to_save.append(uei)
            else:
                to_bulk_create.append(uei)

    UserExternalId.objects.bulk_create(to_bulk_create)
    for uei in to_save:
        uei.save()
    logger.info('Created %s user external ids...', len(to_bulk_create))
    logger.info('Updated %s user external ids...', len(to_save))



    for eudonet_key, attribute_name in user_attributes_mapping.items():
        attribute = attributes[attribute_name]
        serialize = attribute.get_kind()['serialize']

        to_bulk_create = []
        to_save = []
        to_delete = []

        logger.info('Creating attributes %s...', attribute_name)
        atvs = {atv.object_id: atv for atv in AttributeValue.objects.filter(object_id__in=user_ids, attribute=attribute)}
        for row in data:
            user = user_by_guid[row['guid']]
            value = row[eudonet_key]
            atv = atvs.get(user.pk, AttributeValue(
                content_type=user_ct,
                object_id=user.pk,
                attribute=attribute,
                verified=False,
                multiple=False))
            if not value:
                if atv.pk:
                    to_delete.append(atv.pk)
            else:
                serialized = serialize(value)
                if not atv.pk:
                    atv.content = serialized
                    to_bulk_create.append(atv)
                elif atv.content != serialized:
                    atv.content = serialized
                    to_save.append(atv)

        AttributeValue.objects.bulk_create(to_bulk_create)
        for atv in to_save:
            atv.save()
        AttributeValue.objects.filter(pk__in=to_delete).delete()

        logger.info('Created %s %s attributes ...', len(to_bulk_create), attribute_name)
        logger.info('Updated %s %s attributes ...', len(to_save), attribute_name)
        logger.info('Deleted %s %s attributes ...', len(to_delete), attribute_name)

    if len(sys.argv) < 3 or sys.argv[2] != 'nofake':
        raise ValueError('fake')
