from rest_framework import serializers
from rest_framework.exceptions import ValidationError, ParseError

from apps.mtm.serializers import MaterialSerializer
from apps.pum.models import PuOrder
from apps.sam.models import Order
from apps.system.models import Dept, User
from apps.utils.constants import EXCLUDE_FIELDS_BASE, EXCLUDE_FIELDS_DEPT, EXCLUDE_FIELDS
from apps.utils.serializers import CustomModelSerializer
from apps.mtm.models import Material
from .models import MIO, MaterialBatch, MIOItem, WareHouse, MIOItemA, MaterialBatchA, MIOItemw
from django.db import transaction
from server.settings import get_sysconfig


class WareHourseSerializer(CustomModelSerializer):
    class Meta:
        model = WareHouse
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS_DEPT


class MaterialBatchAListSerializer(CustomModelSerializer):
    material_ = MaterialSerializer(source='material', read_only=True)

    class Meta:
        model = MaterialBatchA
        fields = ['material', 'batch', 'rate', 'mb', 'id', 'material_']


class MaterialBatchSerializer(CustomModelSerializer):
    warehouse_name = serializers.CharField(
        source='warehouse.name', read_only=True)
    material_name = serializers.StringRelatedField(
        source='material', read_only=True)
    supplier_name = serializers.StringRelatedField(
        source='supplier', read_only=True)
    material_ = MaterialSerializer(source='material', read_only=True)

    class Meta:
        model = MaterialBatch
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS_BASE


class MaterialBatchDetailSerializer(CustomModelSerializer):
    warehouse_name = serializers.CharField(
        source='warehouse.name', read_only=True)
    material_name = serializers.CharField(
        source='material.name', read_only=True)
    material_ = MaterialSerializer(source='material', read_only=True)
    assemb = MaterialBatchAListSerializer(
        source='a_mb', read_only=True, many=True)
    supplier_name = serializers.StringRelatedField(
        source='supplier', read_only=True)

    class Meta:
        model = MaterialBatch
        fields = '__all__'


class MIOListSerializer(CustomModelSerializer):
    create_by_name = serializers.CharField(
        source='create_by.name', read_only=True)
    submit_user_name = serializers.CharField(
        source='submit_user.name', read_only=True)
    do_user_name = serializers.CharField(
        source='do_user.name', read_only=True)
    mio_user_name = serializers.CharField(
        source='mio_user.name', read_only=True)
    belong_dept_name = serializers.CharField(
        source='belong_dept.name', read_only=True)
    mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
    supplier_name = serializers.CharField(
        source='supplier.name', read_only=True)
    customer_name = serializers.CharField(
        source='customer.name', read_only=True)
    order_number = serializers.CharField(source='order.number', read_only=True)
    pu_order_number = serializers.CharField(
        source='pu_order.number', read_only=True)

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


class MIOItemACreateSerializer(CustomModelSerializer):
    class Meta:
        model = MIOItemA
        fields = ['material', 'batch', 'zhuidu',
                  'b_zuidawaijing', 'g_zuidaneijing']

class MIOItemwCreateSerializer(CustomModelSerializer):
    class Meta:
        model = MIOItemw
        fields = ["number", "note"]

class MIOItemwSerializer(CustomModelSerializer):
    class Meta:
        model = MIOItemw
        fields = "__all__"

class MIOItemwTestSerializer(CustomModelSerializer):
    class Meta:
        model = MIOItemw
        fields = ["test_user", "defect_json", "note", "test_json", "is_testok", "test_time", "qct"]
        extra_kwargs = {
            'test_user': {'required': True},
            'defect_json': {'required': True},
            'test_json': {'required': True},
            'is_testok': {'required': True},
            'test_time': {'required': True},
            'qct': {'required': True},
        }

class MIOItemCreateSerializer(CustomModelSerializer):
    assemb = MIOItemACreateSerializer(
        label='组合件信息', many=True, write_only=True, required=False)
    mioitemw_ = MIOItemwCreateSerializer(many=True, required=False)

    class Meta:
        model = MIOItem
        fields = ['mio', 'warehouse', 'material',
                  'batch', 'count', 'assemb', 'is_testok', 'mioitemw_']

    def create(self, validated_data):
        mio = validated_data['mio']
        material: Material = validated_data['material']
        batch = validated_data['batch']
        if mio.state != MIO.MIO_CREATE:
            raise ValidationError('出入库记录非创建中不可新增')
        # 生产领料要校验是否进行检验
        # 某些客户此处无需校验
        check_test_when_do_out = get_sysconfig('mes.check_test_when_do_out', True)
        if  check_test_when_do_out and mio.type == MIO.MIO_TYPE_DO_OUT:
            mis = MIOItem.objects.filter(batch=batch, material=material, mio__type__in=[MIO.MIO_TYPE_PUR_IN, MIO.MIO_TYPE_DO_IN, MIO.MIO_TYPE_OTHER_IN])
            if mis.exists() and (not mis.exclude(test_date=None).exists()):
                raise ValidationError('该批次的物料未经检验')
        with transaction.atomic():
            count = validated_data["count"]
            batch = validated_data["batch"]
            assemb = validated_data.pop('assemb', [])
            mioitemw_ = validated_data.pop('mioitemw_', [])
            instance = super().create(validated_data)
            assemb_dict = {}
            for i in assemb:
                assemb_dict[i['material'].id] = i
            if material.is_assemb and '_in' in mio.type:  # 仅入库且是组合件的时候需要填写下一级
                components = material.components
                for k, v in components.items():
                    if k in assemb_dict:
                        mia = assemb_dict[k]
                        MIOItemA.objects.create(
                            mioitem=instance, rate=v, **mia)
                    else:
                        raise ParseError('缺少组合件')
            if material.tracking == Material.MA_TRACKING_SINGLE:
                if count == 1 and len(mioitemw_) == 0:
                    MIOItemw.objects.create(mioitem=instance, number=batch)
                elif count == 1 and len(mioitemw_) >= 1:
                    MIOItemw.objects.create(mioitem=instance, number=mioitemw_[0]['number'], note=mioitemw_[0]['note'])
                elif count > 1 and len(mioitemw_) == count:
                    for item in mioitemw_:
                        MIOItemw.objects.create(mioitem=instance, number=item['number'], note=item['note'])
                else:
                    raise ParseError('单个明细信息不匹配')
        return instance


class MIOItemAListSerializer(CustomModelSerializer):
    material_ = MaterialSerializer(source='material', read_only=True)
    material_name = serializers.StringRelatedField(
        source='material', read_only=True)

    class Meta:
        model = MIOItemA
        fields = ['material', 'batch', 'rate', 'mioitem',
                  'id', 'material_', 'material_name']


class MIOItemSerializer(CustomModelSerializer):
    warehouse_name = serializers.CharField(
        source='warehouse.name', read_only=True)
    material_ = MaterialSerializer(source='material', read_only=True)
    assemb = MIOItemAListSerializer(
        source='a_mioitem', read_only=True, many=True)
    material_name = serializers.StringRelatedField(
        source='material', read_only=True)
    inout_date = serializers.DateField(source='mio.inout_date', read_only=True)
    test_user_name = serializers.CharField(source='test_user.name', read_only=True)
    mioitemw_ = MIOItemwSerializer(source='w_mioitem', read_only=True, many=True)

    class Meta:
        model = MIOItem
        fields = '__all__'
    


class MIODoSerializer(CustomModelSerializer):
    belong_dept = serializers.PrimaryKeyRelatedField(
        label="车间", queryset=Dept.objects.all(), required=True)
    do_user = serializers.PrimaryKeyRelatedField(
        label="执行人", queryset=User.objects.all(), required=True)
    note = serializers.CharField(
        required=False, allow_blank=True)

    class Meta:
        model = MIO
        fields = ['id', 'number', 'note', 'do_user',
                  'belong_dept', 'type', 'inout_date', 'mgroup']
        extra_kwargs = {'inout_date': {'required': True}, 'do_user': {'required': True}}

    def validate(self, attrs):
        if 'mgroup' in attrs and attrs['mgroup']:
            attrs['belong_dept'] = attrs['mgroup'].belong_dept
        return attrs
    
    def create(self, validated_data):
        if validated_data['type'] not in [MIO.MIO_TYPE_DO_OUT, MIO.MIO_TYPE_DO_IN]:
            raise ValidationError('出入库类型错误')
        return super().create(validated_data)

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


class MIOSaleSerializer(CustomModelSerializer):
    # order = serializers.PrimaryKeyRelatedField(
    #     label="订单", queryset=Order.objects.all(), required=True)
    note = serializers.CharField(
        required=False, allow_blank=True)

    class Meta:
        model = MIO
        fields = ['id', 'number', 'note', 'order', 'inout_date', 'customer']
        extra_kwargs = {'inout_date': {'required': True}}

    def create(self, validated_data):
        validated_data['type'] = MIO.MIO_TYPE_SALE_OUT
        order: Order = validated_data.get('order', None)
        if order:
            if order.state in [Order.ORDER_CREATE, Order.ORDER_DELIVERED]:
                raise ValidationError('销售订单状态错误')
            validated_data['customer'] = order.customer
            if order.belong_dept:
                validated_data['belong_dept'] = order.belong_dept
        return super().create(validated_data)

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


class MIOPurSerializer(CustomModelSerializer):
    # pu_order = serializers.PrimaryKeyRelatedField(
    #     label="采购订单", queryset=PuOrder.objects.all(), required=True)
    note = serializers.CharField(
        required=False, allow_blank=True)

    class Meta:
        model = MIO
        fields = ['id', 'number', 'note', 'pu_order', 'inout_date', 'supplier']
        extra_kwargs = {'inout_date': {'required': True}}

    def create(self, validated_data):
        validated_data['type'] = MIO.MIO_TYPE_PUR_IN
        pu_order: PuOrder = validated_data.get('pu_order', None)
        if pu_order:
            if pu_order.state in [PuOrder.PUORDER_CREATE, PuOrder.PUORDER_DONE]:
                raise ValidationError('采购订单状态错误')
            validated_data['supplier'] = pu_order.supplier
            if pu_order.belong_dept:
                validated_data['belong_dept'] = pu_order.belong_dept
        return super().create(validated_data)

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


class MIOOtherSerializer(CustomModelSerializer):
    note = serializers.CharField(
        required=False, allow_blank=True)

    class Meta:
        model = MIO
        fields = ['id', 'number', 'note', 'supplier',
                  'customer', 'type', 'inout_date']
        extra_kwargs = {'inout_date': {'required': True}}

    def create(self, validated_data):
        if validated_data['type'] not in [MIO.MIO_TYPE_OTHER_OUT, MIO.MIO_TYPE_OTHER_IN]:
            raise ValidationError('出入库类型错误')
        return super().create(validated_data)

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


class MIODetailSerializer(MIOListSerializer):
    items = MIOItemSerializer(source='item_mio', many=True, read_only=True)


class MIOItemTestSerializer(CustomModelSerializer):
    class Meta:
        model = MIOItem
        fields = ['id', 'test_date', 'test_user', 'count_notok', 'count_n_zw', 'count_n_tw',
                  'count_n_qp', 'count_n_wq', 'count_n_dl', 'count_n_pb', 'count_n_dxt', 'count_n_js', 'count_n_qx', 'count_n_zz', 'count_n_ysq', 'count_n_qt', 'count_n_hs', 'count_n_b', 'test_note']
        extra_kwargs = {
            'test_date': {'required': True},
            'test_user': {'required': True}
        }

        def validate(self, attrs):
            count_notok = 0
            for i in attrs:
                if 'count_n_' in i:
                    count_notok = count_notok + attrs[i]
            attrs['count_notok'] = count_notok
            return attrs

class MioItemAnaSerializer(serializers.Serializer):
    start_date = serializers.DateField(label='开始日期', required=True)
    end_date = serializers.DateField(label='结束日期', required=True)
    material_cate = serializers.CharField(label='物料系列', required=True)


class MIOItemPurInTestSerializer(CustomModelSerializer):
    class Meta:
        model = MIOItem
        fields = ['id', 'test_date', 'test_user',
                  'count_bag', 'count_sampling', 'weight_kgs', 'is_testok', 'test_note']
        extra_kwargs = {
            'test_date': {'required': True},
            'test_user': {'required': True}
        }

    def validate(self, attrs):
        if 'count_sampling' in attrs and attrs['count_sampling']:
            pass
        else:
            weight_kgs = attrs['weight_kgs']
            attrs['weight_kgs'] = [float(i) for i in weight_kgs]
            attrs['count_sampling'] = len(attrs['weight_kgs'])
        return super().validate(attrs)
