# -*- coding: utf-8 -*-
# Generated by Django 1.11.15 on 2018-12-16 21:15
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
from django.db.models import Q
import django.db.models.deletion

from itertools import chain


def getFullName(obj):
    '''
    This function replaces the fullName property for StaffMembers and the
    get_full_name() method for Users, since those methods are not available
    in the migration.
    '''
    if hasattr(obj, 'firstName') and hasattr(obj, 'lastName'):
        return ' '.join([obj.firstName or '', obj.lastName or ''])
    return ' '.join([getattr(obj, 'first_name', ''),getattr(obj, 'last_name', '')])


def createPartyFromName(apps, name):
    '''
    For creating/matching TransactionParty objects using names alone.
    Look for staff members with the same name and match to them first if there is
    exactly one match.  Then, look for users and match them if there is exactly one
    match. Otherwise, just generate a TransactionParty for the name only.
    '''

    TransactionParty = apps.get_model('financial', 'TransactionParty')
    StaffMember = apps.get_model('core', 'StaffMember')
    User = apps.get_model('auth', 'User')

    firstName = name.split(' ')[0]
    lastName = ' '.join(name.split(' ')[1:])

    members = StaffMember.objects.filter(
        firstName__istartswith=firstName, lastName__istartswith=lastName
    )
    users = User.objects.filter(
        first_name__istartswith=firstName, last_name__istartswith=lastName
    )

    if members.count() == 1:
        this_member = members.first()
        party = TransactionParty.objects.get_or_create(
            staffMember=this_member,
            defaults={
                'name': getFullName(this_member),
                'user': this_member.userAccount,
            }
        )[0]
    elif users.count() == 1:
        this_user = users.first()
        party = TransactionParty.objects.get_or_create(
            user=this_user,
            defaults={
                'name': getFullName(this_user),
                'staffMember': getattr(this_user, 'staffmember', None),
            }
        )[0]
    else:
        party = TransactionParty.objects.get_or_create(
            name=name
        )[0]
    return party


def update_payTo(apps, schema_editor):
    '''
    With the new TransactionParty model, the senders and recipients of financial
    transactions are held in one place.  So, we need to loop through old ExpenseItems,
    RevenueItems, and GenericRepeatedExpense and move their old party references
    to the new party model. 
    '''
    TransactionParty = apps.get_model('financial', 'TransactionParty')
    ExpenseItem = apps.get_model('financial', 'ExpenseItem')
    RevenueItem = apps.get_model('financial', 'RevenueItem')
    GenericRepeatedExpense = apps.get_model('financial', 'GenericRepeatedExpense')

    # First, update expense items and Generic repeated expense rules
    for item in chain(
        ExpenseItem.objects.filter(
            Q(payToUser__isnull=False) | Q(payToLocation__isnull=False) | Q(payToName__isnull=False)
        ),
        GenericRepeatedExpense.objects.filter(
            Q(payToUser__isnull=False) | Q(payToLocation__isnull=False) | Q(payToName__isnull=False)
        ),
    ):
        if getattr(item, 'payToUser', None):
            party = TransactionParty.objects.get_or_create(
                user=item.payToUser,
                defaults={
                    'name': getFullName(item.payToUser),
                    'staffMember': getattr(item.payToUser, 'staffmember', None),
                }
            )[0]
        elif getattr(item, 'payToLocation', None):
            party = TransactionParty.objects.get_or_create(
                location=item.payToLocation,
                defaults={
                    'name': item.payToLocation.name,
                }
            )[0]
        elif getattr(item, 'payToName', None):
            party = createPartyFromName(apps, item.payToName)

        item.payTo = party
        item.save()

    # Finally, update revenue items
    for item in RevenueItem.objects.filter(
        Q(receivedFromName__isnull=False)
    ):
        party = createPartyFromName(apps, item.receivedFromName)
        item.receivedFrom = party
        item.save()


class Migration(migrations.Migration):

    dependencies = [
        ('core', '0025_auto_20181109_1631'),
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('financial', '0011_staffdefaultwage'),
    ]

    operations = [
        migrations.CreateModel(
            name='TransactionParty',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(blank=True, max_length=50, null=True, verbose_name='Name')),
                ('location', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.Location', verbose_name='Location')),
                ('staffMember', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.StaffMember', verbose_name='Staff member')),
                ('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='User')),
            ],
            options={
                'verbose_name': 'Transaction party',
                'verbose_name_plural': 'Transaction parties',
                'ordering': ['name'],
                'permissions': (('can_autocomplete_transactionparty', 'Able to use transaction party autocomplete features (in admin forms)'),),
            },
        ),
        migrations.AddField(
            model_name='expenseitem',
            name='payTo',
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='financial.TransactionParty', verbose_name='Pay to'),
        ),
        migrations.AddField(
            model_name='genericrepeatedexpense',
            name='payTo',
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='financial.TransactionParty', verbose_name='Pay to'),
        ),
        migrations.AddField(
            model_name='revenueitem',
            name='receivedFrom',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='financial.TransactionParty', verbose_name='Pay to'),
        ),
        migrations.RunPython(update_payTo),
    ]
