from decimal import Decimal

from rest_framework import serializers

from .models import Invoice, InvoiceItem


class InvoiceItemSerializer(serializers.ModelSerializer):
    line_total = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)

    class Meta:
        model = InvoiceItem
        fields = (
            'id', 'description', 'quantity', 'unit', 'unit_price',
            'tax_rate', 'discount_rate', 'order', 'line_total',
        )
        read_only_fields = ('id',)


class InvoiceSerializer(serializers.ModelSerializer):
    items = InvoiceItemSerializer(many=True, required=False)
    balance_due = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)

    class Meta:
        model = Invoice
        fields = '__all__'
        read_only_fields = (
            'id', 'company', 'created_by', 'amount_paid',
            'invoice_number', 'subtotal', 'tax_amount', 'discount_amount', 'total',
        )

    @staticmethod
    def _compute_totals(items_data):
        subtotal = Decimal('0')
        discount_amount = Decimal('0')
        tax_amount = Decimal('0')
        for item in items_data:
            quantity = item.get('quantity') or Decimal('0')
            unit_price = item.get('unit_price') or Decimal('0')
            discount_rate = item.get('discount_rate') or Decimal('0')
            tax_rate = item.get('tax_rate') or Decimal('0')

            line_base = quantity * unit_price
            line_discount = line_base * discount_rate / 100
            line_after_discount = line_base - line_discount
            line_tax = line_after_discount * tax_rate / 100

            subtotal += line_base
            discount_amount += line_discount
            tax_amount += line_tax

        total = subtotal - discount_amount + tax_amount
        return subtotal, discount_amount, tax_amount, total

    def create(self, validated_data):
        items_data = validated_data.pop('items', [])
        subtotal, discount_amount, tax_amount, total = self._compute_totals(items_data)
        invoice = Invoice.objects.create(
            subtotal=subtotal,
            discount_amount=discount_amount,
            tax_amount=tax_amount,
            total=total,
            **validated_data,
        )
        for item_data in items_data:
            InvoiceItem.objects.create(invoice=invoice, **item_data)
        return invoice

    def update(self, instance, validated_data):
        items_data = validated_data.pop('items', None)
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        if items_data is not None:
            instance.items.all().delete()
            for item_data in items_data:
                InvoiceItem.objects.create(invoice=instance, **item_data)
            subtotal, discount_amount, tax_amount, total = self._compute_totals(items_data)
            instance.subtotal = subtotal
            instance.discount_amount = discount_amount
            instance.tax_amount = tax_amount
            instance.total = total
        instance.save()
        return instance
