from rest_framework import serializers

from account.permissions import assert_shop_access
from shop_management.models.data.opening_balance import FinancialOpeningBalance


class FinancialOpeningBalanceSerializer(serializers.ModelSerializer):
    branch_name = serializers.ReadOnlyField(source="shop.name")
    currency_name = serializers.ReadOnlyField(source="currency.title")
    target_name = serializers.SerializerMethodField()
    balance_type_display = serializers.CharField(source="get_balance_type_display", read_only=True)

    class Meta:
        model = FinancialOpeningBalance
        fields = "__all__"
        read_only_fields = ["opening_number", "status", "journal_entry", "posted_at", "posted_by", "voided_at", "voided_by", "void_reason", "created_by"]

    def get_target_name(self, obj):
        return str(obj.customer or obj.supplier or obj.financial_account or "")

    def validate(self, attrs):
        if self.instance and self.instance.status != FinancialOpeningBalance.Status.DRAFT:
            raise serializers.ValidationError("Posted or void opening balances cannot be edited.")
        shop = attrs.get("shop") or getattr(self.instance, "shop", None)
        request = self.context.get("request")
        if request and shop:
            shop = assert_shop_access(request.user, shop, request)
        customer = attrs.get("customer", getattr(self.instance, "customer", None))
        supplier = attrs.get("supplier", getattr(self.instance, "supplier", None))
        account = attrs.get("financial_account", getattr(self.instance, "financial_account", None))
        currency = attrs.get("currency", getattr(self.instance, "currency", None))
        balance_type = attrs.get("balance_type", getattr(self.instance, "balance_type", None))
        expected = {"CUSTOMER": customer, "SUPPLIER": supplier, "ACCOUNT": account}.get(balance_type)
        if not expected or sum(bool(value) for value in (customer, supplier, account)) != 1:
            raise serializers.ValidationError("Select exactly one target matching the opening type.")
        if shop and (expected.shop_id != shop.pk or currency.shop_id != shop.pk):
            raise serializers.ValidationError("Target and currency must belong to the selected branch.")
        return attrs

    def create(self, validated_data):
        return FinancialOpeningBalance.objects.create(created_by=self.context["request"].user, **validated_data)
