from rest_framework import serializers

from .models import (
    Currency, TaxRate, BankAccount, BudgetCategory, BudgetItem, Invoice, InvoiceLine,
)


class CurrencySerializer(serializers.ModelSerializer):
    """Serializer for Currency."""

    class Meta:
        model = Currency
        fields = ["id", "code", "abbreviation", "name", "is_active", "created_at", "updated_at"]
        read_only_fields = ["id", "created_at", "updated_at"]

    def validate_code(self, value):
        return value.strip().upper()


class TaxRateSerializer(serializers.ModelSerializer):
    """Serializer for TaxRate."""

    class Meta:
        model = TaxRate
        fields = ["id", "name", "rate", "is_default", "is_active", "created_at", "updated_at"]
        read_only_fields = ["id", "created_at", "updated_at"]


class BankAccountSerializer(serializers.ModelSerializer):
    """Org bank account for receiving money. One+ per currency."""

    class Meta:
        model = BankAccount
        fields = [
            "id", "label", "bank_name", "account_number", "account_holder",
            "branch", "swift_code", "currency", "is_default", "is_active",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class BudgetCategorySerializer(serializers.ModelSerializer):
    """Serializer for BudgetCategory with item-count rollup."""
    item_count = serializers.SerializerMethodField()

    class Meta:
        model = BudgetCategory
        fields = ["id", "code", "name", "description", "item_count", "created_at", "updated_at"]
        read_only_fields = ["id", "code", "created_at", "updated_at", "item_count"]

    def get_item_count(self, obj) -> int:
        cnt = getattr(obj, "item_count_anno", None)
        return cnt if cnt is not None else obj.items.count()


class BudgetItemSerializer(serializers.ModelSerializer):
    """Serializer for BudgetItem."""
    category_name = serializers.SerializerMethodField()
    parent_code = serializers.SerializerMethodField()

    class Meta:
        model = BudgetItem
        fields = [
            "id", "code", "category", "category_name", "parent", "parent_code",
            "name", "notes", "created_at", "updated_at",
        ]
        read_only_fields = ["id", "code", "created_at", "updated_at"]

    def get_category_name(self, obj):
        return obj.category.name if obj.category_id else None

    def get_parent_code(self, obj):
        return obj.parent.code if obj.parent_id else None

    def validate(self, attrs):
        parent = attrs.get("parent")
        category = attrs.get("category") or getattr(self.instance, "category", None)
        if parent is not None:
            if category is not None and parent.category_id != category.id:
                raise serializers.ValidationError("Parent item must be in the same category.")
            if self.instance is not None and parent.id == self.instance.id:
                raise serializers.ValidationError("An item cannot be its own parent.")
        return attrs


class InvoiceLineSerializer(serializers.ModelSerializer):
    """A billed line. `amount` is computed on save (quantity × unit_price)."""

    class Meta:
        model = InvoiceLine
        fields = ["id", "description", "quantity", "unit_price", "amount"]
        read_only_fields = ["id", "amount"]


class InvoiceSerializer(serializers.ModelSerializer):
    """Receivable invoice (we bill a donor). Lines are nested and writable."""
    lines = InvoiceLineSerializer(many=True, required=False)
    donor_name = serializers.CharField(source="donor.name", read_only=True, default=None)
    project_name = serializers.CharField(source="project.name", read_only=True, default=None)
    event_name = serializers.CharField(source="event.name", read_only=True, default=None)

    class Meta:
        model = Invoice
        fields = [
            "id", "invoice_number", "donor", "donor_name", "project", "project_name",
            "event", "event_name", "currency", "subtotal", "tax", "total",
            "issue_date", "due_date", "status", "paid_at", "notes", "lines",
            "created_at", "updated_at",
        ]
        read_only_fields = [
            "id", "invoice_number", "donor_name", "project_name", "event_name",
            "subtotal", "total", "created_at", "updated_at",
        ]

    def create(self, validated_data):
        lines = validated_data.pop("lines", [])
        invoice = Invoice.objects.create(**validated_data)
        for line in lines:
            InvoiceLine.objects.create(invoice=invoice, **line)
        invoice.recompute_totals()
        invoice.save(update_fields=["subtotal", "total"])
        return invoice

    def update(self, instance, validated_data):
        lines = validated_data.pop("lines", None)
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        if lines is not None:
            # Replace the line set wholesale — simplest correct semantics.
            instance.lines.all().delete()
            for line in lines:
                InvoiceLine.objects.create(invoice=instance, **line)
        instance.recompute_totals()
        instance.save(update_fields=["subtotal", "total"])
        return instance
