from datetime import timezone
from typing import List
from django.db import transaction
from rest_framework import serializers
from rest_framework.views import APIView
from apps.em.models import Equipment
from apps.em.serializers import EquipmentSerializer
from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer
from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep
from apps.pm.filters import SubproductionProgressFilterSet
from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin
from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from django.shortcuts import render
from apps.sam.models import Order
from rest_framework.exceptions import APIException
from rest_framework.response import Response
from rest_framework.decorators import action
from django.db.models import F
from utils.tools import ranstr
# Create your views here.

def updateOrderPlanedCount(order):
    """
    更新订单已排数量
    """
    planed_count = 0
    plans = ProductionPlan.objects.filter(order=order)
    for i in plans:
        planed_count = planed_count + i.count
    order.planed_count = planed_count
    order.save()

class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModelMixin, GenericViewSet):
    """
    生产计划
    """
    perms_map = {'*': '*'}
    queryset = ProductionPlan.objects.select_related('order', 'order__contract', 'product')
    serializer_class = ProductionPlanSerializer
    search_fields = ['number']
    filterset_fields = ['product', 'order']
    ordering_fields = ['id']
    ordering = ['-id']

    def get_serializer_class(self):
        if self.action in ['create']:
            return ProductionPlanCreateFromOrderSerializer
        elif self.action == 'list':
            return ProductionPlanSerializer
        return super().get_serializer_class()
        
    @transaction.atomic()
    def create(self, request, *args, **kwargs):
        data = request.data
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        if data.get('order', None):
            order = Order.objects.get(pk=data['order'])
            if order.planed_count >= data['count'] or data['count'] > 0:
                pass
            else:
                raise APIException('排产数量错误')
            instance = serializer.save(create_by=request.user, product=order.product, number='JH'+ranstr(7))
            updateOrderPlanedCount(instance.order)
        return Response()
    
    @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PlanDestorySerializer)
    def deletes(self, request, pk=None):
        """
        批量物理删除
        """
        ProductionPlan.objects.filter(id__in=request.data.get('ids', [])).delete(soft=False)
        return Response()
    
    @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=GenSubPlanSerializer)
    def gen_subplan(self, request, pk=None):
        """
        生成子计划
        """
        production_plan=self.get_object()
        if production_plan.is_planed:
            raise APIException('已生成子计划')
        subps = SubProduction.objects.filter(product=production_plan.product).order_by('process__number')
        for index, i in enumerate(subps):
            steps = Step.objects.filter(usedstep__subproduction=i, usedstep__subproduction__is_deleted=False, 
                                        usedstep__is_deleted=False, is_deleted=False).values('id', 'number', 'name', 'usedstep__remark')
            instance = SubProductionPlan.objects.create(production_plan=production_plan, subproduction=i,
                start_date=production_plan.start_date, end_date=production_plan.end_date, 
                workshop=i.process.workshop, process=i.process, create_by=request.user,
                steps = list(steps), number=production_plan.number + '-' + str(index+1))
            # 生成子计划物料需求/进度
            for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
                spro = SubProductionProgress.objects.create(material=m.material, type=m.type,
                is_main=m.is_main,
                 count=m.count*production_plan.count, subproduction_plan=instance)
        production_plan.is_planed=True
        production_plan.save()
        return Response()

class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateModelMixin, GenericViewSet):
    """
    子生产计划-列表/修改
    """
    perms_map = {'*': '*'}
    queryset = SubProductionPlan.objects.select_related('process', 'workshop', 'subproduction', 'main_product', 'production_plan__product')
    search_fields = []
    serializer_class = SubProductionPlanListSerializer
    filterset_fields = ['production_plan', 'process', 'state', 'main_product', 'workshop']
    ordering_fields = ['process__number']
    ordering = ['process__number']

    def get_serializer_class(self):
        if self.action == 'list':
            return SubProductionPlanListSerializer
        elif self.action == 'update':
            return SubProductionPlanUpdateSerializer
        return super().get_serializer_class()

    @action(methods=['get'], detail=True, perms_map={'get':'*'}, serializer_class=SubProductionProgressSerializer)
    def progress(self, request, pk=None):
        """
        生产进度详情
        """
        obj = self.get_object()
        serializer = SubProductionProgressSerializer(instance=obj.progress_subplan, many=True)
        return Response(serializer.data)

    @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
    def issue(self, request, pk=None):
        """
        下达任务
        """
        obj = self.get_object()
        if obj.state == SubProductionPlan.SUBPLAN_STATE_PLANING:
            obj.state = SubProductionPlan.SUBPLAN_STATE_ASSGINED
            obj.save()
            return Response()
        raise APIException('计划状态有误')
    
    @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
    def start(self, request, pk=None):
        """
        开始生产
        """
        obj = self.get_object()
        if obj.state in [SubProductionPlan.SUBPLAN_STATE_ASSGINED, SubProductionPlan.SUBPLAN_STATE_ACCEPTED]:
            obj.state = SubProductionPlan.SUBPLAN_STATE_WORKING
            obj.start_date_real = timezone.now()
            obj.save()
            return Response()
        raise APIException('计划状态有误')
    
    @action(methods=['get'], detail=True, perms_map={'get':'*'}, serializer_class=serializers.Serializer)
    def pick_need_(self, request, pk=None):
        """
        领料需求清单
        """
        obj = self.get_object()
        instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=SubprodctionMaterial.SUB_MA_TYPE_IN)
        serializer = SubProductionProgressSerializer(instance=instance, many=True)
        return Response(serializer.data)
    
    @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
    def pick_need(self, request, pk=None):
        """
        领料需求清单/库存数
        """
        obj = self.get_object()
        instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=SubprodctionMaterial.SUB_MA_TYPE_IN)
        serializer = SubProductionProgressSerializer(instance=instance, many=True)
        need = serializer.data
        materials = []
        for i in need:
            materials.append(i['material'])
        objs = MaterialBatch.objects.filter(material__id__in=materials, count__gt=0).order_by('material__number')
        have = MaterialBatchSerializer(instance=objs, many=True).data
        return Response({'need':need, 'have':have})

class SubProductionProgressViewSet(ListModelMixin, GenericViewSet):
    """
    生产进度
    """
    perms_map = {'*': '*'}
    queryset = SubProductionProgress.objects.select_related('material', 'subproduction_plan')
    search_fields = []
    serializer_class = SubProductionProgressSerializer
    filterset_class = SubproductionProgressFilterSet
    ordering_fields = ['id']
    ordering = ['id']

class ResourceViewSet(GenericViewSet):
    
    perms_map = {'*': '*'}
    @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=ResourceCalListSerializer)
    def cal(self, request, pk=None):
        """
        物料消耗计算
        """
        rdata = request.data
        serializer = self.get_serializer(data=rdata)
        serializer.is_valid(raise_exception=True)
        res_d_list = []
        res = []
        for i in rdata:
            # 计算输入物料
            materials = SubprodctionMaterial.objects.filter(subproduction__product__id=i['id'], 
            subproduction__is_deleted=False, is_deleted=False, material__type__in=[3,4], type=1).order_by('material__number')\
                .values('material__id', 'material__name', 'material__number', 'material__type', 'count', 'material__count')
            l_m = list(materials)
            for m in l_m:
                if m['material__id'] in res_d_list:
                    index = res_d_list.index(m['material__id'])
                    res[index]['count'] = res[index]['count'] + m['count']*i['count']
                else:
                    res_d_list.append(m['material__id'])
                    res.append({'id':m['material__id'], 'name':m['material__name'],
                     'type':m['material__type'], 'number':m['material__number'], 
                     'count':m['count']*i['count'], 'inv_count':m['material__count']})
        return Response(res)

    @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=ResourceCalListSerializer)
    def cal_equip(self, request, pk=None):
        """
        设备状态查看
        """
        rdata = request.data
        serializer = self.get_serializer(data=rdata)
        serializer.is_valid(raise_exception=True)
        rdata_l = []
        for i in rdata:
            rdata_l.append(i['id'])
        subproductions = SubProduction.objects.filter(product__id__in=rdata_l, is_deleted=False)
        steps = Step.objects.filter(usedstep__is_deleted=False, usedstep__subproduction__in=subproductions)
        equips = Equipment.objects.filter(step_equips__in=steps, is_deleted=False).distinct()
        serializer = EquipmentSerializer(instance=equips, many=True)
        return Response(serializer.data)


