from decimal import Decimal

from rest_framework import serializers
from apps.utils.serializers import CustomModelSerializer
from apps.sam.models import Customer, Contract, Order, OrderItem, ContractRecord
from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE
from rest_framework.exceptions import ValidationError
from apps.mtm.serializers import MaterialSerializer


class CustomerSerializer(CustomModelSerializer):
    class Meta:
        model = Customer
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS + ['belong_dept']


class ContractSerializer(CustomModelSerializer):
    customer_name = serializers.CharField(
        source='customer.name', read_only=True)
    create_by_name = serializers.CharField(
        source='create_by.name', read_only=True)

    class Meta:
        model = Contract
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS + ['belong_dept', 'invoice']


class OrderSerializer(CustomModelSerializer):
    customer_name = serializers.CharField(
        source='customer.name', read_only=True)
    contract_number = serializers.CharField(
        source='contract.number', read_only=True)
    create_by_name = serializers.CharField(
        source='create_by.name', read_only=True)
    update_by_name = serializers.CharField(
        source='update_by.name', read_only=True)

    class Meta:
        model = Order
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS + \
            ['belong_dept', 'state', 'submit_time']

    def validate(self, attrs):
        contract = attrs.get('contract', None)
        if contract:
            attrs['customer'] = contract.customer
        if attrs.get('customer', None) is None:
            raise ValidationError('未选择客户')
        return attrs

    def update(self, instance, validated_data):
        if instance.state != Order.ORDER_CREATE:
            raise ValidationError('订单信息不可编辑')
        return super().update(instance, validated_data)


class OrderItemSerializer(CustomModelSerializer):
    material_ = MaterialSerializer(source='material', read_only=True)
    order_ = OrderSerializer(source='order', read_only=True)

    class Meta:
        model = OrderItem
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS_BASE + ['delivered_count']

    def validate(self, attrs):
        order = attrs['order']
        if order.state != Order.ORDER_CREATE:
            raise ValidationError('该订单状态下不可创建')
        return attrs

    def create(self, validated_data):
        order = validated_data['order']
        material = validated_data['material']
        if OrderItem.objects.filter(order=order, material=material).exists():
            raise ValidationError('该产品已选择!')
        return super().create(validated_data)

    def update(self, instance, validated_data):
        validated_data.pop('product', None)
        validated_data.pop('order', None)
        return super().update(instance, validated_data)


class ContractRecordSerializer(CustomModelSerializer):
    contract_number = serializers.CharField(source='contract.number', read_only=True)
    customer_name = serializers.CharField(source='contract.customer.name', read_only=True)

    class Meta:
        model = ContractRecord
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS + ['belong_dept']

    def validate(self, attrs):
        contract = attrs.get('contract', getattr(self.instance, 'contract', None))
        amount = attrs.get('amount', getattr(self.instance, 'amount', None))
        if contract is None or amount is None:
            return attrs
        if contract.status == Contract.STATUS_TERMINATED:
            raise ValidationError('合同已终止，不可操作到款流水')
        qs = ContractRecord.objects.filter(contract=contract)
        if self.instance is not None:
            qs = qs.exclude(id=self.instance.id)
        total = sum((item.amount for item in qs), Decimal('0.00')) + amount
        contract_amount = Decimal(str(contract.amount or 0))
        if total > contract_amount:
            raise ValidationError('累计到款金额不可超过合同金额')
        return attrs
