from django_filters import rest_framework as filters
from apps.wpm.models import (SfLog, StLog, WMaterial, Mlog, Mlogbw,
                             Handover, Mgroup, Mlogb, Mtask, BatchSt, Handoverb)
from apps.mtm.models import Route, Material
from django.db.models import Q, Exists, OuterRef
from rest_framework.exceptions import ParseError
from datetime import datetime

class SfLogFilter(filters.FilterSet):
    class Meta:
        model = SfLog
        fields = {
            "mgroup": ["exact"],
            "shift": ["exact"],
            "team": ["exact"],
            "leader": ["exact"],
            "team__belong_dept": ["exact"],
            "end_time": ["day", "month", "year", "lt"],
            "start_time": ["gte"]
        }


class StLogFilter(filters.FilterSet):
    class Meta:
        model = StLog
        fields = {
            "mgroup": ["exact"],
            "mgroup__name": ["exact"],
            "start_time": ["day", "month", "year", "gte", "lte"],
            "sflogs__team": ["exact"],
            "end_time": ["isnull"],
            "sflog": ["exact"],
            "sflogs": ["exact"],
            "cate": ["exact"],
        }


class WMaterialFilter(filters.FilterSet):
    mgroupx = filters.CharFilter(label='MgroupId', method='filter_mgroupx')
    tag = filters.CharFilter(label="todo/done", method="filter_tag")
    mtaskx = filters.CharFilter(label='MtaskId', method='filter_mtaskx')
    route = filters.CharFilter(label='routeId', method='filter_route')
    material__process__exclude = filters.CharFilter(field_name="material__process", lookup_expr="exact", exclude=True)
    mlog_date_start = filters.DateFilter(label="产出开始", method="filter_mlog_date_start")
    mlog_date_end = filters.DateFilter(label="产出结束", method="filter_mlog_date_end")
    current_merged = filters.BooleanFilter(label="是否本工段新合成的批", method="filter_current_merged")

    def filter_mlog_date_start(self, queryset, name, value):
        mgroupId = self.data.get("mgroup", None)
        mgroupxId = self.data.get("mgroupx", None)
        mgroupId = mgroupId if mgroupId else mgroupxId
        if mgroupId:
            pass
        else:
            raise ParseError("请提供工段查询条件")
        if value:
            mlog_date_start = value
            mlog_date_end = self.data.get("mlog_date_end", datetime.now().date())
            return queryset.filter(batch__in=
            Mlogb.objects.filter(mlog__mgroup__id=mgroupId, material_out__isnull=False,
            mlog__handle_date__range=(mlog_date_start, mlog_date_end)).values_list("batch", flat=True))
        return queryset

    def filter_mlog_date_end(self, queryset, name, value):
        return queryset

    def filter_mgroupx(self, queryset, name, value):
        return WMaterial.ava_qs(mgroup=Mgroup.objects.get(id=value), qs=queryset)
    
    def filter_tag(self, queryset, name, value):
        mgroupId = self.data.get("mgroup", None)
        mgroupxId = self.data.get("mgroupx", None)
        mgroupId = mgroupId if mgroupId else mgroupxId
        if mgroupId:
            process = Mgroup.objects.get(id=mgroupId).process
            
            queryset = queryset.filter(material__type__in=[Material.MA_TYPE_MAINSO, Material.MA_TYPE_HALFGOOD, Material.MA_TYPE_GOOD])
            if value == "todo":
                matIds = process.get_canin_mat_ids()
                qs = queryset.filter(material__id__in=matIds).exclude(state=WMaterial.WM_REPAIRED)|queryset.filter(state=WMaterial.WM_REPAIR, mgroup__id=mgroupId)
                return qs
            elif value == "done":
                matoutIds = process.get_canout_mat_ids()
                qs = queryset.filter(material__id__in=matoutIds).exclude(state=WMaterial.WM_REPAIR)|queryset.filter(state=WMaterial.WM_REPAIRED, mgroup__id=mgroupId)
            elif value == "canfix":
                matoutIds = process.get_canout_mat_ids()
                qs = queryset.filter(state=WMaterial.WM_REPAIR, mgroup__id=mgroupId)| queryset.filter(material__id__in=matoutIds, state=WMaterial.WM_NOTOK)
            return qs
        else:
            raise ParseError("请提供工段查询条件")

    def filter_mtaskx(self, queryset, name, value):
        mtask = Mtask.objects.get(id=value)
        if mtask.route and mtask.route.batch_bind:
            return WMaterial.mat_in_qs(mtask=Mtask.objects.get(id=value), qs=queryset.filter(count__gt=0))
        return queryset

    def filter_route(self, queryset, name, value):
        try:
            route = Route.objects.get(id=value)
        except Route.DoesNotExist:
            raise ParseError('生产路线不存在!')
        return queryset.filter(material=route.material_in)|queryset.filter(material__in=route.materials.all())
    
    def filter_current_merged(self, queryset, name, value):
        sub_qs = Handoverb.objects.filter(
            wm_to=OuterRef("pk"),
            handover__mtype=Handover.H_MERGE,
            handover__submit_time__isnull=False
        )
        if value is True:
            return queryset.annotate(_has_merge=Exists(sub_qs)).filter(_has_merge=True)
        elif value is False:
            return queryset.annotate(_has_merge=Exists(sub_qs)).filter(_has_merge=False)
        return queryset

    class Meta:
        model = WMaterial
        fields = {
            "material": ["exact", "in"],
            "state": ["exact", "in"],
            "material__type": ["exact", "in"],
            "material__name": ["exact", "in", "contains"],
            "material__process": ["exact", "in"],
            "material__process__name": ["exact", "contains", "in"],
            "belong_dept": ["exact", "isnull"],
            "belong_dept__name": ["exact", "in"],
            "batch": ["exact", "contains"],
            "mgroup": ["exact", "in", "isnull"],
            "mgroup__name": ["exact", "in"],
            "count": ["gte", "lte", "exact"],
            "notok_sign": ["exact", "in", "isnull"],
            "count_xtest": ["gte", "isnull"],
            "supplier": ["exact"],
            "defect": ["exact", "isnull"]
        }

class MlogFilter(filters.FilterSet):
    cbatch = filters.CharFilter(label='批次号', method='filter_cbatch')
    cnumber = filters.CharFilter(label='单个编号', method='filter_cnumber')
    class Meta:
        model = Mlog
        fields = {
            "mtask": ["exact", "in"],
            "batch": ["exact"],
            "handle_date": ["exact"],
            "handle_user": ["exact"],
            "mgroup": ["exact"],
            "mtask__mgroup__belong_dept__name": ["exact", "contains", "in"],
            "mgroup__belong_dept__name": ["exact", "in", "contains"],
            "mgroup__name": ["exact", "in", "contains"],
            "submit_time": ["isnull"],
            "fmlog": ["exact"],
            "b_mlog__batch": ["exact"],
            "b_mlog__w_mlogb__number": ["exact"],
        }
    
    def filter_cbatch(self, queryset, name, value):
        qs1 = queryset.filter(batch=value)
        qs2 = queryset.filter(b_mlog__batch=value)
        return qs1.union(qs2)
    
    def filter_cnumber(self, queryset, name, value):
        return queryset.filter(b_mlog__w_mlogb__number=value).distinct()


class HandoverFilter(filters.FilterSet):
    cbatch = filters.CharFilter(label='批次号', method='filter_cbatch')
    mgroup = filters.CharFilter(label='MgroupId', method='filter_mgroup')
    mgroupx = filters.CharFilter(label='MgroupId', method='filter_mgroupx')
    dept = filters.CharFilter(label='DeptId', method='filter_dept')

    def filter_mgroup(self, queryset, name, value):
        return queryset.filter(
            Q(send_mgroup_id=value) | Q(recive_mgroup_id=value)
        )

    def filter_mgroupx(self, queryset, name, value):
        dept = Mgroup.objects.get(id=value).belong_dept
        return queryset.filter(
            Q(send_mgroup_id=value)
            | Q(recive_mgroup_id=value)
            | Q(send_dept=dept, send_mgroup__isnull=True)
            | Q(recive_dept=dept, recive_mgroup__isnull=True)
        )
    
    def filter_dept(self, queryset, name, value):
        return queryset.filter(
            Q(send_dept_id=value) | Q(recive_dept_id=value)
        )
    
    def filter_cbatch(self, queryset, name, value):
        qs1 = queryset.filter(Q(batch=value)|Q(new_batch=value)|Q(wm__batch=value))
        qs2 = queryset.filter(Q(b_handover__batch=value))
        return qs1.union(qs2)

    class Meta:
        model = Handover
        fields = {
            "id": ["exact"],
            "batch": ["exact", "contains"],
            "material": ["exact", "in"],
            "send_user": ["exact"],
            "send_dept": ["exact"],
            "send_dept__name": ["exact"],
            "recive_dept": ["exact"],
            "recive_dept__name": ["exact"],
            "send_date": ["exact"],
            "material__type": ["exact", "in"],
            "material__process": ["exact", "in"],
            "material__process__name": ["exact", "contains", "in"],
            "submit_time": ["isnull"],
            "mlog": ["isnull"],
            "send_mgroup": ["exact"],
            "send_mgroup__name": ["exact"],
            "recive_mgroup": ["exact"],
            "recive_mgroup__name": ["exact"],
            "type": ["exact", "in"],
            "mtype": ["exact", "in"],
            "b_handover__batch": ["exact"],
            "b_handover__w_handoverb__number": ["exact"]
        }


class MlogbFilter(filters.FilterSet):
    type = filters.CharFilter(label="in/out", method='filter_type')
    class Meta:
        model = Mlogb
        fields = {
            "mlog": ["exact"],
            "mtask": ["exact"],
            "wm_in": ["exact"],
            "mlog__submit_time": ["isnull"],
            "wm_in__state": ["exact"],
            "material_in": ["exact", "isnull"],
            "material_out": ["exact", "isnull"],
            "parent": ["exact", "isnull"],
        }
    
    def filter_type(self, queryset, name, value):
        if value:
            if value == 'in':
                return queryset.filter(material_in__isnull=False)
            elif value == 'out':
                return queryset.filter(material_out__isnull=False)
            return queryset
        return queryset.none()
    

class BatchStFilter(filters.FilterSet):
    batch__startswith__in = filters.CharFilter(method='filter_batch')
    data__has_key = filters.CharFilter(method='filter_data')
    with_source_near = filters.CharFilter(label='来源', method='filter_source_near')
    with_zt_big = filters.CharFilter(label='附带直通大批', method='filter_source_near')

    def filter_source_near(self, queryset, name, value):
        return queryset

    def filter_data(self, queryset, name, value):
        return queryset.filter(data__has_key=value)

    class Meta:
        model = BatchSt
        fields = {
            "batch": ["exact", "contains", "startswith"],
            "zt_batch": ["exact", "isnull"],
            "version": ["exact", "gte", "lte"],
            "first_time": ["exact", "gte", "lte", "isnull"],
            "last_time": ["exact", "gte", "lte", "isnull"],
            "update_time": ["exact", "gte", "lte"],
            "material_start": ["exact"],
            "material_start__cate": ["exact"],
            "material_start__type": ["exact"],
            "material_start__process": ["exact"]
        }

    def filter_batch(self, queryset, name, value):
        v_list = value.split(',')
        query = Q()
        for value in v_list:
            query |= Q(batch__startswith=value)
        return queryset.filter(query)
    

class MlogbwFilter(filters.FilterSet):
    type = filters.CharFilter(label="in/out", method='filter_type')
    class Meta:
        model = Mlogbw
        fields = {
            "mlogb": ["exact"],
            "mlogb__mlog": ["exact"],
            "mlogb__mlog__mgroup": ["exact"],
            "mlogb__mlog__submit_time": ["isnull"],
            "wpr": ["exact"],
            "ftest": ["isnull"],
            "ftest__is_ok": ["exact"],
            "ftest__defect_main": ["exact"]
        }

    def filter_type(self, queryset, name, value):
        if value:
            if value == 'in':
                return queryset.filter(mlogb__material_in__isnull=False)
            elif value == 'out':
                return queryset.filter(mlogb__material_out__isnull=False)
            return queryset
        return queryset.none()
