# Create your models here.
import math
from decimal import Decimal

from django.db import models
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from core.common.enums import ChoiceEnum, Currency
from core.common.models import AbstractAuditableModel


class Budget(AbstractAuditableModel):
    name = models.CharField(_("Budget name"), max_length=255)
    groups = models.ManyToManyField('budget.BudgetGroup', through='budget.BudgetToGroupRelation')
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_("An owner of the budget"),
                              on_delete=models.CASCADE)

    def __str__(self):
        return f"Budget: {self.name}"

    @cached_property
    def incomes(self):
        return self.transfers.filter(Transfer.TransferTypes.INCOME.name)

    @cached_property
    def outcomes(self):
        return self.transfers.filter(Transfer.TransferTypes.OUTCOME.name)


class BudgetToGroupRelation(AbstractAuditableModel):
    group = models.ForeignKey('budget.BudgetGroup', on_delete=models.CASCADE)
    budget = models.ForeignKey('budget.Budget', on_delete=models.CASCADE)


class BudgetGroupToUserRelation(AbstractAuditableModel):
    group = models.ForeignKey('budget.BudgetGroup', on_delete=models.CASCADE)
    collaborator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)


class BudgetGroup(AbstractAuditableModel):
    name = models.CharField(_("Group name"), max_length=255)
    budgets = models.ManyToManyField('budget.Budget', through='budget.BudgetToGroupRelation')
    collaborators = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                           through='budget.BudgetGroupToUserRelation')

    def __str__(self):
        return f"Budget group {self.name}"


class Transfer(AbstractAuditableModel):
    class TransferTypes(ChoiceEnum):
        INCOME = "Income"
        OUTCOME = "Outcome"

    PRECISION = 100
    budget = models.ForeignKey('budget.Budget', related_name='transfers', on_delete=models.CASCADE)
    transfer_type = models.CharField(_("Transfer type"), choices=TransferTypes.choices(), max_length=255)
    monetary_units = models.PositiveIntegerField(_("Monetary units (e.g. 10$==1000 monetary units, cents)"))
    currency = models.CharField(_("Currency iso alpha 3"), max_length=3, choices=Currency.choices())
    description = models.CharField(_("Description of the transfer"), max_length=255, blank=True, null=True)

    def __init__(self, *args, **kwargs):
        amount = kwargs.pop('amount', None)
        if amount is not None:
            kwargs.update({'monetary_units': self.amount_to_monetary_units(amount)})
        super().__init__(*args, **kwargs)

    def __str__(self):
        return f"{self.transfer_type} transfer of {self.currency.upper()}{self.amount}"

    @property
    def amount(self):
        return self.monetary_units / self.PRECISION

    def amount_to_monetary_units(self, amount: Decimal):
        return math.trunc(amount * self.PRECISION)
