# -*- coding: utf-8 -*-
# This file is part of k4ever, a point-of-sale system
#   Contact............  <k4ever@lists.someserver.de>
#   Website............  http://k4ever.someserver.de/
#   Bug tracker........  http://k4ever.someserver.de/report
#
# Licensed under GNU Affero General Public License v3 or later


from django.db import models
from django.core.validators import *
from django.contrib.auth.models import User
from django.db.models.deletion import SET_NULL
from django.db.models.signals import pre_delete
from decimal import Decimal

from validator import validate_notZero

class TransactionType(models.Model):
	""" Type for a :class:`Transaction`. States how the money has
	    been added to the account and if somebody needs to check
		if it was payed. """
	name = models.CharField(max_length=100)
	needsCheck = models.BooleanField(default=True)
	
	def __unicode__(self):
		return unicode(self.name)

class Transaction(models.Model):
	"""Represents a money transaction into the users account. """
	user = models.ForeignKey(User)
	transactionType = models.ForeignKey(TransactionType, verbose_name='Typ')
	dateTime = models.DateTimeField(auto_now_add=True)
	amount = models.DecimalField(max_digits=8, decimal_places=2, validators=[validate_notZero])
	checked = models.BooleanField(default=False)
	
	def __unicode__(self):
		return u"%s for user %s (%s),%schecked" % (self.amount, self.user, self.transactionType, (self.checked and " " or " not "))
	
	def save(self, *args, **kwargs):
		profile = self.user.get_profile()
		if self.id == None:
			# insert
			profile.balance += self.amount
		else:
			# update
			oldobj = Transaction.objects.get(id=self.id)
			if oldobj.user != self.user:
				oldprofile = oldobj.user.get_profile()
				oldprofile.balance -= oldobj.amount
				oldprofile.save()
				# just to be save, reget profile
				profile = self.user.get_profile()
				profile.balance += self.amount
			else:
				profile.balance += (self.amount-oldobj.amount)
		profile.save()
		super(Transaction, self).save(*args, **kwargs)
	
	@staticmethod
	def pre_delete_signal(sender, instance, **kwargs):
		profile = instance.user.get_profile()
		profile.balance -= instance.amount
		profile.save()
		
pre_delete.connect(Transaction.pre_delete_signal, sender=Transaction)

class VirtualTransaction(models.Model):
	""" Represents a transaction between two users. """
	user = models.ForeignKey(User, null=True, on_delete=SET_NULL)
	recipient = models.ForeignKey(User, related_name='receivedtransaction', null=True, on_delete=SET_NULL, verbose_name=u'Empfänger')
	dateTime = models.DateTimeField(auto_now_add=True)
	amount = models.DecimalField(max_digits=8, decimal_places=2, validators=[MinValueValidator(Decimal("0.01"))], verbose_name='Betrag')
	comment = models.CharField(max_length=100, verbose_name='Verwendungszweck')
	
	def __unicode__(self):
		return u"%s ==> %s: %s Euro" % (self.user, self.recipient, self.amount)
	
	@staticmethod
	def moveMoney(fromUser, toUser, amount, commit=True):
		print fromUser, toUser, fromUser == toUser, fromUser.id, toUser.id
		if not (fromUser == toUser):
			fromProfile = fromUser.get_profile()
			toProfile = toUser.get_profile()
			fromProfile.balance -= amount
			toProfile.balance += amount
			if commit:
				fromProfile.save()
				toProfile.save()
	
	def save(self, *args, **kwargs):
		if self.user and self.recipient:
			oldobj = None
			try:
				oldobj = VirtualTransaction.objects.get(id=self.id)
			except VirtualTransaction.DoesNotExist:
				pass

			if oldobj and (oldobj.user != self.user or oldobj.recipient != self.recipient):
				VirtualTransaction.moveMoney(oldobj.recipient, oldobj.user, oldobj.amount)
				VirtualTransaction.moveMoney(self.user, self.recipient, self.amount)
			else:
				tmpAmount = None
				if oldobj == None:
					tmpAmount = self.amount
				else:
					tmpAmount = self.amount - oldobj.amount
				VirtualTransaction.moveMoney(self.user, self.recipient, tmpAmount)
			super(VirtualTransaction, self).save(*args, **kwargs)
	
	@staticmethod
	def pre_delete_signal(sender, instance, **kwargs):
		""" Pre delete signal to ensure consistent balances on object delete. """
		# Only revert if both users exist.
		if instance.user and instance.recipient:
			# revert transaction
			VirtualTransaction.moveMoney(instance.recipient, instance.user, amount)

pre_delete.connect(VirtualTransaction.pre_delete_signal, sender=VirtualTransaction)

