import collections

from django import forms
from django.contrib import admin
from django.forms.models import BaseInlineFormSet

from nodeconductor_assembly_waldur.packages import models


class PackageComponentForm(forms.ModelForm):
    monthly_price = forms.DecimalField(label="Price for 30 days", initial=0, required=True)

    class Meta:
        model = models.PackageComponent
        fields = ('type', 'amount', 'monthly_price', 'price')

    def __init__(self, *args, **kwargs):
        super(PackageComponentForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields['monthly_price'].initial = self.instance.monthly_price

    def clean(self):
        super(PackageComponentForm, self).clean()
        if 'monthly_price' not in self.cleaned_data or 'amount' not in self.cleaned_data:
            return
        type = self.cleaned_data['type']
        monthly_price = self.cleaned_data['monthly_price']
        amount = self.cleaned_data['amount']

        price_min = 10 ** -models.PackageComponent.PRICE_DECIMAL_PLACES
        monthly_price_min = price_min * 30 * amount
        if monthly_price < monthly_price_min:
            raise forms.ValidationError('Monthly price for "%s" should be lower than %s' % (type, monthly_price_min))

        price_max = 10 ** (models.PackageComponent.PRICE_MAX_DIGITS - models.PackageComponent.PRICE_DECIMAL_PLACES)
        monthly_price_max = price_max * 30 * amount
        if monthly_price > monthly_price_max:
            raise forms.ValidationError('Monthly price for "%s" cannot be greater than %s' % (type, monthly_price_max))

    def save(self, commit=True):
        monthly_price = self.cleaned_data.get('monthly_price', None)
        amount = self.cleaned_data.get('amount', 0)
        package_component = super(PackageComponentForm, self).save(commit=commit)
        if amount:
            package_component.price = monthly_price / 30 / amount
        if commit:
            package_component.save()
        return package_component


class PackageComponentInlineFormset(BaseInlineFormSet):
    """
    Formset responsible for package component inlines validation and their initial population.
    """
    form = PackageComponentForm

    def __init__(self, **kwargs):
        # Fill inlines with required component types
        kwargs['initial'] = [{'type': t} for t in models.PackageTemplate.get_required_component_types()]
        super(PackageComponentInlineFormset, self).__init__(**kwargs)

    def clean(self):
        super(PackageComponentInlineFormset, self).clean()
        if any(self._errors):
            return
        # Check whether all required components were filled and are not marked for deletion.
        marked_for_delete = []
        filled = []
        for comp in self.cleaned_data:
            if not comp:
                continue
            elif comp.get('DELETE', False):
                marked_for_delete.append(comp['type'])
            filled.append(comp['type'])
        duplicates = [item for item, count in collections.Counter(filled).items() if count > 1]
        if duplicates:
            raise forms.ValidationError('One or more items are duplicated: %s' % ', '.join(duplicates))

        for t in models.PackageTemplate.get_required_component_types():
            if t not in filled:
                raise forms.ValidationError('%s component must be specified.' % t.capitalize())
            elif t in marked_for_delete:
                raise forms.ValidationError('%s component is required and cannot be deleted.' % t.capitalize())


class PackageComponentInline(admin.TabularInline):
    form = PackageComponentForm
    formset = PackageComponentInlineFormset
    model = models.PackageComponent
    extra = 0
    readonly_fields = ('price', )

    def get_extra(self, request, obj=None, **kwargs):
        if obj:
            return super(PackageComponentInline, self).get_extra(request, obj, **kwargs)
        # On creation number of inlines must be equal to number of required components
        return len(models.PackageTemplate.get_required_component_types())


class PackageTemplateAdmin(admin.ModelAdmin):
    inlines = [PackageComponentInline]
    fields = ('name', 'category', 'description', 'icon_url', 'service_settings')
    list_display = ('name', 'uuid', 'service_settings', 'price', 'monthly_price', 'category')
    list_filter = ('service_settings',)
    search_fields = ('name', 'uuid')


class OpenStackPackageAdmin(admin.ModelAdmin):
    list_display = ('template', 'tenant', 'service_settings')
    list_filter = ('template',)


admin.site.register(models.PackageTemplate, PackageTemplateAdmin)
admin.site.register(models.OpenStackPackage, OpenStackPackageAdmin)

@@ -1228,11 +1228,13 @@
  be 
-low
+great
 er t
@@ -1555,29 +1555,27 @@
 %22 cannot be 
-great
+low
 er than %25s' 

Fix validation messages