from rest_framework import serializers, exceptions
from rest_framework.serializers import ModelSerializer
from apps.em.models import Equipment
from apps.em.serializers import EquipmentSimpleSerializer
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse
from apps.inm.signals import update_inm
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial
from apps.mtm.serializers import MaterialSimpleSerializer, RecordFormSimpleSerializer, StepSimpleSerializer

from apps.pm.models import SubProductionPlan, SubProductionProgress
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from apps.pm.serializers import SubproductionPlanSimpleSerializer
from apps.qm.models import TestRecord, TestRecordItem
from apps.system.serializers import UserSimpleSerializer
from apps.wpm.models import Operation, OperationEquip, OperationMaterial, OperationWproduct, Pick, WMaterial, WProduct, OperationRecord, OperationRecordItem
from django.db import transaction

class PickHalfSerializer(serializers.Serializer):
    id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
    wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all())
                                             , label='半成品ID', required=False) # 从半成品表里直接修改状态

class PickHalfsSerializer(serializers.ListSerializer):
    child = PickHalfSerializer()
class PickDetailSerializer(serializers.Serializer):
    material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
    batch = serializers.CharField(label='物料批次', allow_blank=True)
    warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
    pick_count = serializers.IntegerField(label="领料数量", required=False)
    iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID',required=False, many=True)

class PickSerializer(serializers.Serializer):
    subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
    picks = PickDetailSerializer(many=True) # 从库存里拿

    def create(self, validated_data):
        picks = validated_data.pop('picks')
        sp = validated_data.pop('subproduction_plan')
        if sp.state not in [SubProductionPlan.SUBPLAN_STATE_ASSGINED, SubProductionPlan.SUBPLAN_STATE_ACCEPTED,
                     SubProductionPlan.SUBPLAN_STATE_WORKING]:
            raise exceptions.APIException('该子计划状态错误')
        # if sp.is_picked:
        #     raise exceptions.APIException('该子计划已领料')
        # for i in picks:
        #     try:
        #         instance = MaterialBatch.objects.get(material=i['material'], batch=i['batch'])
        #         if instance.count < i['pick_count']:
        #             raise exceptions.APIException('物料不足')
        #     except:
        #         raise exceptions.APIException('物料不存在')
        # 创建出库记录

        with transaction.atomic():
            fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT, inout_date=timezone.now(), create_by=self.context['request'].user)
            for i in picks:
                isLowLevel = False
                # 更新出库详情
                i['count'] = i.pop('pick_count', 0)
                # 是否勾选每一个
                if 'iproducts' in i and len(i['iproducts'])>0:
                    i['count'] = len(i['iproducts'])
                    isLowLevel = True
                if i['count']>0:
                    if isLowLevel:
                        iproducts = i.pop('iproducts')
                    i['fifo'] = fifo
                    i['is_testok'] = True # 默认检测合格
                    i['subproduction_plan'] = sp
                    fifoitem = FIFOItem.objects.create(**i)
                    # 创建再下一个层级
                    if isLowLevel:
                        mls = []
                        for m in iproducts:
                            ml = {}
                            ml['material'] = m.material
                            ml['number'] = m.number
                            ml['wproduct'] = m.wproduct
                            ml['fifoitem'] = fifoitem
                            mls.append(FIFOItemProduct(**ml))
                        FIFOItemProduct.objects.bulk_create(mls)

                    # 更新车间物料
                    wm, _ = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \
                        subproduction_plan=sp,defaults={
                            'material':i['material'],
                            'batch':i['batch'],
                            'subproduction_plan':sp,
                            'count':0
                        })
                    wm.count = wm.count + i['count']
                    wm.save()
                    # 更新子计划物料情况
                    spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=SubprodctionMaterial.SUB_MA_TYPE_IN)
                    spp.count_pick = spp.count_pick + i['count']
                    spp.save()
                    # if spp.count_pick > spp.count:
                    #     raise exceptions.APIException('超过计划需求数')
                    if isLowLevel:
                        # 更新半成品表
                        wids = IProduct.objects.filter(pk__in=[x.id for x in iproducts]).values_list('wproduct', flat=True)
                        wproducts = WProduct.objects.filter(pk__in=wids)
                        first_step = Step.objects.get(pk=sp.steps[0]['id'])
                        wproducts.update(step=first_step, 
                        act_state=WProduct.WPR_ACT_STATE_TORETEST, is_hidden=False, warehouse=None,
                        subproduction_plan=sp)
            sp.is_picked=True
            sp.state = SubProductionPlan.SUBPLAN_STATE_WORKING #生产中
            sp.state_date_real = timezone.now() #实际开工日期
            sp.save()
            # 创建领料记录
            pick = Pick()
            pick.subproduction_plan = sp
            pick.type = Pick.PICK_FROM_WAREHOUSE
            pick.fifo = fifo
            pick.create_by = self.context['request'].user
            pick.save()
            # 更新库存
            fifo.is_audited = True
            fifo.save()
            update_inm(fifo)
        return fifo
    
class WMaterialListSerializer(serializers.ModelSerializer):
    """
    车间物料
    """
    material_ = MaterialSimpleSerializer(source='material', read_only=True)
    subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
    class Meta:
        model = WMaterial
        fields = '__all__'

class WProductListSerializer(serializers.ModelSerializer):
    """
    半成品列表
    """
    material_ = MaterialSimpleSerializer(source='material', read_only=True)
    step_ = StepSimpleSerializer(source='step', read_only=True)
    class Meta:
        model = WProduct
        fields = '__all__'

class OperationDetailSerializer(serializers.ModelSerializer):
    create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
    step_ = StepSimpleSerializer(source='step', read_only=True)
    class Meta:
        model = Operation
        fields = '__all__'

class OperationListSerializer(serializers.ModelSerializer):
    create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
    step_ = StepSimpleSerializer(source='step', read_only=True)
    wproduct_ = serializers.SerializerMethodField()
    equip_ = serializers.SerializerMethodField()
    record_ = serializers.SerializerMethodField()
    class Meta:
        model = Operation
        fields = '__all__'

    def get_wproduct_(self, obj):
        return WProduct.objects.filter(ow_wproduct__operation=obj).values('id', 'number')
    
    def get_equip_(self, obj):
        return EquipmentSimpleSerializer(instance=Equipment.objects.filter(oe_equip__operation=obj), many=True).data 
    
    def get_record_(self, obj):
        return RecordFormSimpleSerializer(instance=RecordForm.objects.filter(or_form__operation=obj), many=True).data

class OperationCreateSerializer(serializers.Serializer):
    """
    操作创建
    """
    step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
    # subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
    wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label="半成品ID列表", required=False, many=True)
    
    def validate(self, data):
        # subproduction_plan = data['subproduction_plan']
        step = data['step']
        
        # stepIds=[i['id'] for i in subproduction_plan.steps]
        # if step.id not in stepIds:
        #     raise exceptions.APIException('请选择正确的子工序操作')
        
        if 'wproducts' in data and data['wproducts']:
            if step.type == Step.STEP_TYPE_DIV:
                raise exceptions.APIException(_('不可进行此操作'))
            for i in data['wproducts']:
                if i.act_state != WProduct.WPR_ACT_STATE_DOWAIT:
                    raise exceptions.APIException('半成品不在待操作状态')
                # if i.is_executed:
                #     raise exceptions.APIException('不可进行操作')
                # if i.subproduction_plan != subproduction_plan:
                #     raise exceptions.APIException('半成品所属子计划不一致')
                if i.step != step:
                    raise exceptions.APIException('半成品所属子工序不一致')
        else:
            if step.type != Step.STEP_TYPE_DIV:
                raise exceptions.APIException(_('请选择半成品进行操作'))
        return data


class OperationUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Operation
        fields =['use_scrap', 'remark']

class OperationInitSerializer(serializers.Serializer):
    step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
    subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
    wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label="半成品ID列表", required=False, many=True)
    
    def validate(self, data):
        # subproduction_plan = data['subproduction_plan']
        step = data['step']
        
        # stepIds=[i['id'] for i in subproduction_plan.steps]
        # if step.id not in stepIds:
        #     raise exceptions.APIException('请选择正确的子工序操作')
        
        if 'wproducts' in data and data['wproducts']:
            if step.type == Step.STEP_TYPE_DIV:
                raise exceptions.APIException(_('不可进行此操作'))
            for i in data['wproducts']:
                if i.act_state != WProduct.WPR_ACT_STATE_DOWAIT:
                    raise exceptions.APIException('半成品不在待操作状态')
                # if i.subproduction_plan != subproduction_plan:
                #     raise exceptions.APIException('半成品所属子计划不一致')
                if i.step != step:
                    raise exceptions.APIException('半成品所属子工序不一致')
        else:
            if step.type != Step.STEP_TYPE_DIV:
                raise exceptions.APIException(_('请选择半成品进行操作'))
        return data


class DoInputSerializer(serializers.Serializer):
    id = serializers.PrimaryKeyRelatedField(queryset=WMaterial.objects.all(), label='车间物料ID')
    count_input = serializers.IntegerField(min_value=0, label='消耗数量')

class DoOutputSerializer(serializers.Serializer):
    subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
    material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label='物料ID')
    count_output = serializers.IntegerField(min_value=0, label='产出数量')

class OperationRecordItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = OperationRecordItem
        fields = ['form_field', 'field_value']

class OperationRecordSubmitSerializer(serializers.ModelSerializer):
    record_data = OperationRecordItemSerializer(many=True)
    class Meta:
        model = OperationRecord
        fields = ['record_data']

class OperationRecordSerializer(serializers.ModelSerializer):
    record_data = OperationRecordItemSerializer(many=True)
    class Meta:
        model = OperationRecord
        fields = ['form', 'record_data']

class OperationWproductListSerializer(serializers.ModelSerializer):
    material_ = MaterialSimpleSerializer(source='material', read_only=True)
    subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
    class Meta:
        model = OperationWproduct
        fields = '__all__'


class OperationSubmitSerializer(serializers.Serializer):
    step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
    subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
    wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label="半成品ID列表", required=False, many=True)
    input = DoInputSerializer(many=True, required=False)
    output = DoOutputSerializer(many=True, required=False)
    forms = OperationRecordSerializer(many=True, required=False)
    remark = serializers.CharField(required=False, label='操作备注', allow_blank=True, allow_null=True)
    use_scrap = serializers.BooleanField(required=False, default=False)

class WpmTestRecordItemCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = TestRecordItem
        fields = ['form_field', 'field_value', 'is_testok']

class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
    record_data = WpmTestRecordItemCreateSerializer(many=True)
    wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
    is_testok = serializers.BooleanField(required=False)
    
    class Meta:
        model = TestRecord
        fields = ['form', 'record_data', 'is_testok', 'wproduct']

class WpmTestFormInitSerializer(serializers.Serializer):
    wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
    form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=True)
    

class WplanPutInSerializer(serializers.Serializer):
    warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
    remark = serializers.CharField(label="入库备注", required =False)

class WproductPutInSerializer(serializers.Serializer):
    warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
    remark = serializers.CharField(label="入库备注", required =False)

class WproductPutInsSerializer(serializers.Serializer):
    warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
    wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID', many=True)
    remark = serializers.CharField(label="入库备注", required =False)


class OperationEquipListSerializer(serializers.Serializer):
    equip_ = EquipmentSimpleSerializer(source='equip', read_only=True)
    class Meta:
        model = OperationEquip
        fields = '__all__'

class OperationEquipUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = OperationEquip
        fields = ['remark']

class OperationRecordListSerializer(serializers.ModelSerializer):
    form_ = RecordFormSimpleSerializer(source='form', read_only=True)
    class Meta:
        model = OperationRecord
        fields = '__all__'

class OperationMaterialListSerializer(serializers.ModelSerializer):
    material_ = MaterialSimpleSerializer(source='material', read_only=True)
    subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
    class Meta:
        model = OperationMaterial
        fields = '__all__'

class OperationMaterialCreate1Serailizer(serializers.ModelSerializer):
    wmaterial = serializers.PrimaryKeyRelatedField(required=True, queryset=WMaterial.objects.all())
    class Meta:
        model = OperationMaterial
        fields = ['operation', 'wmaterial', 'count']
    
    def validate(self, attrs):
        if attrs['count'] <=0:
            raise exceptions.APIException('消耗物料数量错误')
        return super().validate(attrs)

    def create(self, validated_data):
        wmaterial = validated_data['wmaterial']
        validated_data['material'] = wmaterial.material
        validated_data['subproduction_plan'] = wmaterial.subproduction_plan
        validated_data['batch'] = wmaterial.batch
        validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_IN
        return super().create(validated_data)

class OperationMaterialCreate1ListSerailizer(serializers.ListSerializer):
    child=OperationMaterialCreate1Serailizer()

class OperationMaterialCreate2Serailizer(serializers.ModelSerializer):
    subproduction_progress = serializers.PrimaryKeyRelatedField(required=True, queryset=SubProductionProgress.objects.all())
    class Meta:
        model = OperationMaterial
        fields = ['operation', 'subproduction_progress', 'count']
    
    def create(self, validated_data):
        subproduction_progress = validated_data['subproduction_progress']
        validated_data['material'] = subproduction_progress.material
        validated_data['subproduction_plan'] = subproduction_progress.subproduction_plan
        validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_OUT
        return super().create(validated_data)


class OperationMaterialCreate2ListSerailizer(serializers.ListSerializer):
    child=OperationMaterialCreate2Serailizer()
class OperationMaterialCreate3Serializer(serializers.ModelSerializer):
    material = serializers.PrimaryKeyRelatedField(required=True, queryset=Material.objects.all())
    class Meta:
        model = OperationMaterial
        fields = ['operation', 'material']
    
    def create(self, validated_data):
        validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_TOOL
        return super().create(validated_data)

    