# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-03-12 12:46
from __future__ import unicode_literals

from django.db import migrations, models
from django.db.models import Q, Sum, Max
import django.db.models.deletion
import django.utils.timezone
from django.utils.timezone import timedelta
import enumfields.fields
import enum
import uuid
import wallet.enums
from moneyed import Money


class TrxType(enum.Enum):
    FINALIZED = 0
    PENDING = 1
    CANCELLATION = 2


def forwards_func(apps, schema_editor):
    WalletTransaction = apps.get_model('wallet', 'wallettransaction')
    WalletTransactionStatus = apps.get_model('wallet', 'wallettransactionstatus')

    pre_balance = WalletTransaction.objects \
        .exclude(trx_type=TrxType.PENDING) \
        .aggregate(amount=Sum('amount'))['amount'] or Money(0, 'SEK')

    pendings = WalletTransaction.objects.filter(trx_type=TrxType.PENDING)
    finalized = WalletTransaction.objects.filter(trx_type=TrxType.FINALIZED)
    cancels = WalletTransaction.objects.filter(trx_type=TrxType.CANCELLATION)

    for trx in pendings:
        assert trx.internal_reference is None
        trx.states.create(status=trx.trx_type, date_created=trx.date_created)

    marked_for_deletion = []
    for trx in finalized:
        if trx.internal_reference is None:
            trx.states.create(
                status=TrxType.PENDING,
                date_created=(trx.date_created - timedelta(milliseconds=100))
            )
            trx.states.create(
                status=TrxType.FINALIZED,
                date_created=trx.date_created
            )

        else:
            refs_statuses = trx.internal_reference.states.all()
            assert refs_statuses.count() == 1
            assert refs_statuses.first().status.value == TrxType.PENDING.value
            assert trx.internal_reference.wallet == trx.wallet
            assert trx.internal_reference.amount == trx.amount
            assert trx.internal_reference.reference == trx.reference
            trx.internal_reference.states.create(
                status=TrxType.FINALIZED,
                date_created=trx.date_created
            )
            marked_for_deletion.append(trx.pk)

    for trx in cancels:
        assert trx.internal_reference is not None

        refs_statuses = trx.internal_reference.states.all()
        assert refs_statuses.count() > 0 and refs_statuses.count() < 3
        for ref in refs_statuses:
            status = ref.status.value
            assert status == TrxType.PENDING.value or status == TrxType.FINALIZED.value
        assert trx.internal_reference.wallet == trx.wallet
        assert trx.internal_reference.amount == -trx.amount

        trx.internal_reference.states.create(
            status=TrxType.CANCELLATION,
            date_created=trx.date_created
        )
        marked_for_deletion.append(trx.pk)

    # Remove transaction that acts as duplicated statuses
    WalletTransaction.objects.filter(pk__in=marked_for_deletion).delete()
    # Compute the total balance in the system
    stamps = WalletTransaction.objects.annotate(
        latest_stamp=Max('states__date_created')
    ).values_list('latest_stamp', flat=True)

    post_balance = WalletTransaction.objects.filter(
        (Q(amount__lt=0) & Q(states__status=TrxType.PENDING))
        | (Q(amount__gte=0) & Q(states__status=TrxType.FINALIZED))
    ).exclude(
        Q(states__status=TrxType.CANCELLATION),
        states__date_created__in=stamps
    ).aggregate(amount=Sum('amount'))['amount'] or Money(0, 'SEK')
    # Make sure that the total balance in the system has not changed
    assert pre_balance == post_balance



class Migration(migrations.Migration):

    dependencies = [
        ('wallet', '0011_auto_20170308_2258'),
    ]

    operations = [
        migrations.CreateModel(
            name='WalletTransactionStatus',
            fields=[
                ('date_created', models.DateTimeField(blank=True, default=django.utils.timezone.now, editable=False, null=True, verbose_name='date created')),
                ('date_modified', models.DateTimeField(auto_now=True, null=True, verbose_name='date modified')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
                ('status', enumfields.fields.EnumIntegerField(default=1, enum=TrxType, verbose_name='type')),
            ],
            options={
                'verbose_name': 'transaction status',
                'verbose_name_plural': 'transaction statuses',
                'ordering': ('-date_created',),
            },
        ),
        migrations.AlterField(
            model_name='wallettransaction',
            name='date_created',
            field=models.DateTimeField(blank=True, default=django.utils.timezone.now, editable=False, null=True, verbose_name='date created'),
        ),
        migrations.AddField(
            model_name='wallettransactionstatus',
            name='trx',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='states', to='wallet.WalletTransaction'),
        ),
        migrations.AlterUniqueTogether(
            name='wallettransactionstatus',
            unique_together=set([('trx', 'status')]),
        ),
        migrations.RunPython(forwards_func),
    ]
