# -*- coding: utf-8 -*-
# Akvo RSR is covered by the GNU Affero General Public License.
# See more details in the license.txt file located at the root folder of the Akvo RSR module.
# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.
from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.utils.translation import gettext_lazy as _
from ..fields import ValidXMLCharField
from akvo.codelists.models import BudgetIdentifier, BudgetStatus, BudgetType, Currency
from akvo.codelists.store.default_codelists import (BUDGET_IDENTIFIER, BUDGET_TYPE, BUDGET_STATUS,
                                                    CURRENCY)
from akvo.utils import codelist_choices, codelist_value
[docs]class BudgetItemLabel(models.Model):
    TOTAL_BUDGET_LABEL_ID = 14
    label = ValidXMLCharField(_('label'), max_length=30, unique=True, db_index=True)
    def __str__(self):
        return self.label
    class Meta:
        app_label = 'rsr'
        ordering = ('label',)
        verbose_name = _('budget item label')
        verbose_name_plural = _('budget item labels') 
[docs]class BudgetItem(models.Model):
    # DON'T translate. Need model translations for this to work
    OTHER_LABELS = ['other 1', 'other 2', 'other 3']
    project = models.ForeignKey('Project', on_delete=models.CASCADE, verbose_name=_('project'), related_name='budget_items')
    label = models.ForeignKey(
        BudgetItemLabel, on_delete=models.CASCADE, verbose_name=_('budget item'), null=True, blank=True,
        help_text=_('Select the budget item(s) to indicate how the project budget is divided. '
                    'Use the ‘Other’ fields to add custom budget items.')
    )
    other_extra = ValidXMLCharField(
        max_length=30, null=True, blank=True, verbose_name=_('other label extra info'),
        help_text=_('Enter a description for an "other" budget item.'),
    )
    # Translators: This is the amount of an budget item in a currency (€ or $)
    amount = models.DecimalField(
        _('budget item value'), max_digits=14, decimal_places=2, null=True, blank=True,
        help_text=_('Enter the amount of budget that is set aside for this specific budget item. '
                    'Use a period to denote decimals.')
    )
    # Extra IATI fields
    type = ValidXMLCharField(
        _('budget type'), blank=True, max_length=1, choices=codelist_choices(BUDGET_TYPE),
        help_text=_('Select whether this is an original or revised budget of the project.')
    )
    period_start = models.DateField(
        _('budget item period start'), null=True, blank=True,
        help_text=_('Enter the start date (DD/MM/YYYY) for the budget period.')
    )
    period_end = models.DateField(
        _('budget item period end'), null=True, blank=True,
        help_text=_('Enter the end date (DD/MM/YYYY) for the budget period.')
    )
    value_date = models.DateField(
        _('budget item value date'), null=True, blank=True,
        help_text=_('Enter the date (DD/MM/YYYY) to be used for determining the exchange rate for '
                    'currency conversions.')
    )
    currency = ValidXMLCharField(_('currency'), max_length=3, blank=True,
                                 choices=codelist_choices(CURRENCY))
    status = ValidXMLCharField(
        _('status'), max_length=1, blank=True, choices=codelist_choices(BUDGET_STATUS),
        help_text=_('The status explains whether the budget being reported is indicative or has '
                    'been formally committed.'))
    def __str__(self):
        if self.label:
            if self.label.label == 'Other' and self.other_extra:
                budget_unicode = self.other_extra
            else:
                budget_unicode = self.label.label
        else:
            budget_unicode = '%s' % _('No budget item specified')
        if self.amount and self.currency:
            budget_unicode += ' - %s %s' % (str('{:,}'.format(int(self.amount))), self.currency)
        elif self.amount and not self.currency:
            budget_unicode += ' - %s %s' % (str('{:,}'.format(int(self.amount))), self.project.currency)
        else:
            budget_unicode += ' - %s' % _('No amount specified')
        if self.type == '2':
            budget_unicode += ' %s' % _('(Revised)')
        return budget_unicode
[docs]    def clean(self):
        # Don't allow a start date before an end date
        if self.period_start and self.period_end and (self.period_start > self.period_end):
            raise ValidationError(
                {'period_start': '%s' % _('Period start cannot be at a later time than period '
                                          'end.'),
                 'period_end': '%s' % _('Period start cannot be at a later time than period '
                                        'end.')}
            ) 
[docs]    def get_label(self):
        "Needed since we have to have a vanilla __str__() method for the admin"
        if self.label and self.label.label in self.OTHER_LABELS:
            # display "other" if other_extra is empty.
            # Translating here without translating the other labels seems corny
            return "other" if self.other_extra is None else self.other_extra.strip()
        elif self.label and self.label.label:
            return self.label.label
        else:
            return str(self) 
[docs]    def get_currency(self):
        if self.currency:
            return self.currency
        else:
            return self.project.currency 
[docs]    def iati_type(self):
        return codelist_value(BudgetType, self, 'type') 
[docs]    def iati_type_unicode(self):
        return str(self.iati_type()) 
[docs]    def iati_currency(self):
        if self.currency:
            return codelist_value(Currency, self, 'currency')
        else:
            return codelist_value(Currency, self.project, 'currency') 
[docs]    def iati_currency_unicode(self):
        return str(self.iati_currency()) 
[docs]    def iati_status(self):
        return codelist_value(BudgetStatus, self, 'status') 
[docs]    def iati_status_unicode(self):
        return str(self.iati_status()) 
    class Meta:
        app_label = 'rsr'
        ordering = ('label',)
        verbose_name = _('budget item')
        verbose_name_plural = _('budget items')
        ordering = ('pk',) 
[docs]class CountryBudgetItem(models.Model):
    project = models.ForeignKey('Project', on_delete=models.CASCADE, verbose_name=_('project'), related_name='country_budget_items')
    code = ValidXMLCharField(
        _('country budget item'), max_length=10, blank=True,
        choices=codelist_choices(BUDGET_IDENTIFIER),
        help_text=_('This item encodes the alignment of activities with both the functional and '
                    'administrative classifications used in the recipient country’s Chart of '
                    'Accounts. This applies to both on- and off-budget activities.')
    )
    description = ValidXMLCharField(
        _('country budget item description'), max_length=100, blank=True,
    )
    percentage = models.DecimalField(
        _('country budget item percentage'), blank=True, null=True, max_digits=4, decimal_places=1,
        validators=[MaxValueValidator(100), MinValueValidator(0)],
        help_text=_('If more than one identifier is reported, the percentage share must be '
                    'reported and all percentages should add up to 100 percent. Use a period to '
                    'denote decimals.')
    )
    def __str__(self):
        return self.iati_code().name if self.code else '%s' % _('No code specified')
[docs]    def iati_code(self):
        return codelist_value(BudgetIdentifier, self, 'code') 
[docs]    def iati_code_unicode(self):
        return str(self.iati_code()) 
    class Meta:
        app_label = 'rsr'
        verbose_name = _('country budget item')
        verbose_name_plural = _('country budget items')
        ordering = ('pk',)