from apps.utils.constants import EXCLUDE_FIELDS
from apps.utils.serializers import CustomModelSerializer
from rest_framework import serializers
from rest_framework.exceptions import ValidationError, ParseError
from datetime import datetime

from .models import SfLog, StLog, SfLogExp, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog
from apps.system.models import Dept, User
from apps.system.serializers import UserSimpleSerializer
from apps.pm.models import Mtask
from apps.wpm.tasks import cal_enstat_when_pcoal_heat_change, cal_enstat_when_team_change, cal_exp_duration_hour
from apps.wpm.services import get_sflog
from apps.mtm.models import Mgroup, TeamMember, Shift, Material
from apps.mtm.serializers import MaterialSimpleSerializer
from django.db import transaction
from django.utils import timezone


class OtherLogSerializer(CustomModelSerializer):
    class Meta:
        model = OtherLog
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS


class StLogSerializer(CustomModelSerializer):
    mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
    current_sflog = serializers.CharField(label='当前处理值班', write_only=True)
    current_note = serializers.CharField(
        label='值班处理备注', write_only=True, allow_blank=True)

    class Meta:
        model = StLog
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS + \
            ['is_shutdown', 'sflog', 'duration']

    def create(self, validated_data):
        current_sflog = validated_data.pop('current_sflog')
        current_note = validated_data.pop('note', '')
        with transaction.atomic():
            validated_data['sflog'] = get_sflog(
                validated_data['mgroup'], validated_data['start_time'])
            if current_sflog != validated_data['sflog']:
                raise ParseError('值班时间与发生时间不一致')
            instance = super().create(validated_data)
            SfLogExp.objects.create(
                sflog=current_sflog, stlog=instance, create_by=self.context['request'].user, note=current_note)
            return instance

    def update(self, instance, validated_data):
        if instance.is_shutdown:  # 停机不可编辑end_time
            validated_data.pop('end_time', None)
        if instance.end_time:
            raise ParseError('该异常已结束无需编辑')
        with transaction.atomic():
            validated_data.pop('mgroup', None)
            validated_data.pop('start_time', None)
            end_time = validated_data.pop('end_time', None)
            current_sflog = validated_data.pop('current_sflog')
            current_note = validated_data.pop('current_note', '')
            instance = super().update(instance, validated_data)
            if end_time:  # 需要把涉及到的sflog都拉入
                cal_exp_duration_hour(instance.id)
            try:
                sflogexp = SfLogExp.objects.get(
                    stlog=instance.stlog, sflog=current_sflog)
                sflogexp.note = current_note
                sflogexp.save()
            except SfLogExp.DoesNotExist:
                raise ParseError('该异常无需本班填写')
            return instance

    def validate(self, attrs):
        now = timezone.now()
        start_time: datetime = attrs['start_time']
        end_time: datetime = attrs.get('end_time', None)
        if start_time > now:
            raise ParseError('开始时间应为历史时间')
        if end_time:
            if end_time > now:
                raise ParseError('开始时间应为历史时间')
            if end_time > start_time:
                attrs['duration'] = (
                    end_time - start_time).total_seconds / 3600
            else:
                raise ParseError('结束时间应大于开始时间')
        return super().validate(attrs)


class SfLogSerializer(CustomModelSerializer):
    mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
    team_name = serializers.CharField(source='team.name', read_only=True)
    shift_name = serializers.CharField(source='shift.name', read_only=True)
    leader_name = serializers.CharField(source='leader.name', read_only=True)

    class Meta:
        model = SfLog
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS + \
            ['mgroup', 'start_time', 'end_time', 'belong_dept']
        extra_kwargs = {
            'team': {'required': True},
            'leader': {'required': True}
        }

    def update(self, instance, validated_data):
        with transaction.atomic():
            old_pcoal_heat = instance.pcoal_heat
            old_team = instance.team
            instance: SfLog = super().update(instance, validated_data)
            new_pcoal_heat = instance.pcoal_heat
            new_team = instance.team
            mgroup: Mgroup = instance.mgroup
            if new_pcoal_heat != old_pcoal_heat and mgroup.need_enm:
                cal_enstat_when_pcoal_heat_change.delay(instance.id)
            if new_team != old_team:
                default_state = 'pending'
                if timezone.now() > instance.end_time:
                    default_state = 'normal'
                # 分配班组时创建人员到岗情况
                for item in TeamMember.objects.filter(team=new_team, mgroup=instance.mgroup):
                    AttLog.objects.get_or_create(sflog=instance, user=item.user, defaults={
                                                 'sflog': instance, 'user': item.user, 'post': item.post, 'state': default_state, 'create_by': self.context['request'].user})
                if mgroup.need_enm:
                    cal_enstat_when_team_change.delay(instance.id)
            return instance
    # def to_internal_value(self, data):
    #     if hasattr(self.Meta, 'update_fields') and self.context['request'].method in ['PUT', 'PATCH']:
    #         u_fields = self.Meta.update_fields
    #         new_data = {key: data[key] for key in u_fields if key in data}
    #         return super().to_internal_value(new_data)
    #     return super().to_internal_value(data)


class SflogExpSerializer(CustomModelSerializer):
    # mgroup = serializers.CharField(source='sflog.mgroup.id', read_only=True)
    # mgroup_name = serializers.CharField(
    #     source='sflog.mgroup.name', read_only=True)
    # stlog_ = StLogSerializer(source='stlog', read_only=True)
    # happen_time = serializers.DateTimeField(required=True, label='发生时间')
    # cate = serializers.CharField(required=True, label='原因类别')

    class Meta:
        model = SfLogExp
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS + ['sflog', 'stlog', 'duration']


class WMaterialSerializer(CustomModelSerializer):
    material_ = MaterialSimpleSerializer(source='material', read_only=True)
    material_name = serializers.StringRelatedField(
        source='material', read_only=True)
    belong_dept_name = serializers.CharField(
        source='belong_dept.name', read_only=True)

    class Meta:
        model = WMaterial
        fields = '__all__'


class MlogbSerializer(CustomModelSerializer):
    material_out_ = MaterialSimpleSerializer(
        source='material_out', read_only=True)
    material_out_name = serializers.StringRelatedField(
        source='material_out', read_only=True)

    class Meta:
        model = Mlogb
        fields = ['id', 'material_out', 'count_ok',
                  'material_out_', 'material_out_name']


class MlogSerializer(CustomModelSerializer):
    belong_dept = serializers.CharField(
        source='mgroup.belong_dept.id', read_only=True)
    belong_dept_name = serializers.CharField(
        source='mgroup.belong_dept.name', read_only=True)
    mgroup_name = serializers.CharField(
        source='mgroup.name', read_only=True)
    mtask_count = serializers.IntegerField(
        source='mtask.count', 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)
    handovers = serializers.PrimaryKeyRelatedField(
        source='handover_mlog', read_only=True, many=True)
    material_out_ = MaterialSimpleSerializer(
        source='material_out', read_only=True)
    material_out_name = serializers.StringRelatedField(
        source='material_out', read_only=True)
    material_in_name = serializers.StringRelatedField(
        source='material_in', read_only=True)
    handle_user_name = serializers.CharField(
        source='handle_user.name', read_only=True)
    handle_user_2_name = serializers.CharField(
        source='handle_user_2.name', read_only=True)
    handle_leader_name = serializers.CharField(
        source='handle_leader.name', read_only=True)
    equipment_name = serializers.StringRelatedField(
        source='equipment', read_only=True)
    equipment_2_name = serializers.StringRelatedField(
        source='equipment_2', read_only=True)
    shift = serializers.PrimaryKeyRelatedField(
        label='班次ID', queryset=Shift.objects.all(), required=True)
    mgroup = serializers.PrimaryKeyRelatedField(
        label='工段ID', queryset=Mgroup.objects.all(), required=True
    )
    material_out = serializers.PrimaryKeyRelatedField(
        label='产物ID', queryset=Material.objects.all(), required=True
    )
    shift_name = serializers.CharField(source='shift.name', read_only=True)
    mlogb = MlogbSerializer(
        label='多产出件信息', many=True, required=False)
    handle_users_ = UserSimpleSerializer(
        source='handle_users', many=True, read_only=True)
    equipments_name = serializers.StringRelatedField(
        source='equipments', read_only=True, many=True)

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

    def create(self, validated_data):
        mtask: Mtask = validated_data.get('mtask', None)
        # batch = validated_data['batch']
        # handle_date = validated_data['handle_date']
        # handle_user = validated_data.get('handle_user', None)
        if mtask:
            validated_data['mgroup'] = mtask.mgroup
            validated_data['material_in'] = mtask.material_in
            material_out = mtask.material_out
            validated_data['material_out'] = material_out
            validated_data['handle_date'] = mtask.start_date
            # if  not WMaterial.objects.filter(batch=batch).exists():
            #     raise ValidationError('批次号不存在')
        else:
            mgroup = validated_data['mgroup']
            material_out = validated_data['material_out']
            if not (mgroup and material_out):
                raise ValidationError('缺少工段或产物!')
        # if handle_user:
        #     if Mlog.objects.filter(mtask=mtask, batch=batch, handle_date=handle_date, handle_user=handle_user).exists():
        #         raise ValidationError('存在相同的日志记录')
        # else:
        #     if Mlog.objects.filter(mtask=mtask, batch=batch, handle_date=handle_date).exists():
        #         raise ValidationError('存在相同的日志记录')
        with transaction.atomic():
            mlogb = validated_data.pop('mlogb', [])
            instance = super().create(validated_data)
            brotherId_should_list = material_out.brothers
            if brotherId_should_list:
                if mlogb:
                    for item in mlogb:
                        if item['material_out'].id in brotherId_should_list:
                            Mlogb.objects.create(
                                mlog=instance, material_out=item['material_out'], count_ok=item['count_ok'])
                else:
                    raise ValidationError('缺少产出物信息')
        return instance

    def update(self, instance, validated_data):
        validated_data.pop('mtask', None)
        validated_data.pop('mgroup', None)
        if instance.mtask:
            validated_data.pop('handle_date', None)
        # validated_data.pop('handle_user', None)
        with transaction.atomic():
            mlogb = validated_data.pop('mlogb', [])
            instance = super().update(instance, validated_data)
            brotherId_should_list = instance.material_out.brothers
            if brotherId_should_list:
                if mlogb:
                    for item in mlogb:
                        id = item.get('id', None)
                        if id:
                            mlogb = Mlogb.objects.get(id=id)
                            mlogb.count_ok = item['count_ok']
                            mlogb.save()
                        # elif item['material_out'].id in brotherId_should_list:
                        #     Mlogb.objects.create(
                        #         mlog=instance, material_out=item['material_out'], count_ok=item['count_ok'])
                else:
                    raise ValidationError('缺少产出物信息')
        return instance

    def validate(self, attrs):
        mtask = attrs.get('mtask', None)
        if mtask:
            if mtask.start_date == mtask.end_date:
                attrs['handle_date'] = mtask.start_date
            else:
                if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date:
                    pass
                else:
                    raise ValidationError('操作日期错误')
            if mtask.state != Mtask.MTASK_ASSGINED:
                raise ValidationError(f'{mtask.mgroup.name}_不可提交日志!')
        return attrs


class MlogRevertSerializer(serializers.Serializer):
    change_reason = serializers.CharField(label='撤回原因')


class MlogRelatedSerializer(serializers.Serializer):
    mtask = serializers.PrimaryKeyRelatedField(
        label='小任务ID', queryset=Mtask.objects.all())


class DeptBatchSerializer(serializers.Serializer):
    belong_dept_name = serializers.CharField(label='车间名称')


class HandoverSerializer(CustomModelSerializer):
    material = serializers.PrimaryKeyRelatedField(
        required=True, label='物料ID', queryset=Material.objects.all())
    send_user_name = serializers.CharField(
        source='send_user.name', read_only=True)
    recive_user_name = serializers.CharField(
        source='recive_user.name', read_only=True)
    material_ = MaterialSimpleSerializer(source='material', read_only=True)
    material_name = serializers.StringRelatedField(
        source='material', read_only=True)

    def validate(self, attrs):
        if attrs.get('mlog', None):
            attrs['send_mgroup'] = attrs['mlog'].mgroup
            attrs['send_dept'] = attrs['mlog'].mgroup.belong_dept
        elif attrs.get('wm', None):
            attrs['send_dept'] = attrs['wm'].belong_dept
        return super().validate(attrs)

    class Meta:
        model = Handover
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS


class GenHandoverSerializer(serializers.Serializer):
    mlogs = serializers.PrimaryKeyRelatedField(
        label='mlog的ID列表', queryset=Mlog.objects.all(), many=True)
    recive_dept = serializers.PrimaryKeyRelatedField(
        label='交送车间', queryset=Dept.objects.all())
    recive_user = serializers.PrimaryKeyRelatedField(
        label='接收人', queryset=User.objects.all())
    send_user = serializers.PrimaryKeyRelatedField(
        label='交送人', queryset=User.objects.all())
    send_date = serializers.DateField(label='交送日期')


class GenHandoverWmSerializer(serializers.Serializer):
    wm = serializers.PrimaryKeyRelatedField(
        label='车间物料ID', queryset=WMaterial.objects.all())
    send_mgroup = serializers.PrimaryKeyRelatedField(
        label='送料工段ID', queryset=Mgroup.objects.all())
    recive_dept = serializers.PrimaryKeyRelatedField(
        label='交送车间', queryset=Dept.objects.all())
    recive_user = serializers.PrimaryKeyRelatedField(
        label='接收人', queryset=User.objects.all())
    send_user = serializers.PrimaryKeyRelatedField(
        label='交送人', queryset=User.objects.all())
    send_date = serializers.DateField(label='交送日期')
    count = serializers.IntegerField(label='交送数量')

    def validate(self, attrs):
        if attrs['count'] <= 1:
            raise ValidationError('交送数量必须大于1')
        return attrs


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


class AttLogSerializer(CustomModelSerializer):
    mgroup_name = serializers.CharField(
        source='sflog.mgroup.name', read_only=True)
    user_name = serializers.CharField(source='user.name', read_only=True)
    post_name = serializers.CharField(source='post.name', read_only=True)
    belong_dept_name = serializers.CharField(
        source='sflog.mgroup.belong_dept.name', read_only=True)

    class Meta:
        model = AttLog
        fields = '__all__'
