from django.db import models
from apps.utils.models import CommonADModel, CommonBDModel, BaseModel
from apps.mtm.models import Mgroup, Team, Shift, Material, Route
from apps.pm.models import Mtask, Mtaskb
from apps.system.models import User
from django.utils.timezone import localtime
from apps.em.models import Equipment
from apps.system.models import Dept
from apps.pum.models import Supplier
from django.db.models import Sum, Subquery
from django.utils.translation import gettext_lazy as _
from rest_framework.exceptions import ParseError

# Create your models here.

class BatchSt(BaseModel):
    """
    批次统计表
    """
    batch = models.TextField("批次号")
    last_time = models.DateTimeField("最后操作时间", null=True, blank=True)
    data = models.JSONField("数据", default=list, blank=True)

class SfLog(CommonADModel):
    """值班记录
    """
    mgroup = models.ForeignKey(
        Mgroup, verbose_name='关联工段', on_delete=models.CASCADE)
    team = models.ForeignKey(Team, verbose_name='班组',
                             on_delete=models.CASCADE, null=True, blank=True)
    shift = models.ForeignKey(
        Shift, verbose_name='当班班次', on_delete=models.CASCADE)
    leader = models.ForeignKey(
        'system.user', verbose_name='班长', on_delete=models.CASCADE, null=True, blank=True)
    work_date = models.DateField('值班日期', null=True, blank=True)
    start_time = models.DateTimeField('值班开始')
    end_time = models.DateTimeField('值班结束')
    note = models.TextField('其他备注', null=True, blank=True)
    stlogs = models.ManyToManyField(
        'wpm.stlog', verbose_name='关联异常记录', through='wpm.sflogexp', related_name='sflog_stlogs')
    last_test_time = models.DateTimeField('最后质检时间', null=True, blank=True)
    total_sec_now = models.PositiveIntegerField('总时长动', default=0)
    total_sec = models.PositiveIntegerField('总时长', default=43200)
    shut_sec = models.PositiveIntegerField('停机时长', default=0)
    pcoal_heat = models.FloatField('煤粉热值', null=True, blank=True)

    @property
    def get_ymd(self):
        """
        返回值班记录所属年月日
        """
        start_time_local = localtime(self.start_time)
        return start_time_local.year, start_time_local.month, start_time_local.day


class StLog(CommonADModel):
    """
    异常记录
    """
    title = models.CharField('异常名称', max_length=20, default='')
    is_shutdown = models.BooleanField('是否是停机', default=False)
    mgroup = models.ForeignKey(
        Mgroup, verbose_name='关联工段', on_delete=models.CASCADE)
    sflog = models.ForeignKey(
        SfLog, on_delete=models.SET_NULL, verbose_name='发生时所在值班', null=True, blank=True)
    sflogs = models.ManyToManyField(
        'wpm.sflog', verbose_name='关联所有当班', through='wpm.sflogexp', related_name='stlog_sflogs')
    start_time = models.DateTimeField('发生时间')
    end_time = models.DateTimeField('结束时间', null=True, blank=True)
    duration_sec = models.PositiveIntegerField('持续时长(s)', null=True, blank=True)
    cate = models.CharField('原因类别', max_length=10, null=True, blank=True)
    reason = models.TextField('事件原因', null=True, blank=True)
    measure = models.TextField('处置措施', null=True, blank=True)
    handler = models.CharField('处理人', null=True, blank=True, max_length=100)

    class Meta:
        unique_together = ('mgroup', 'start_time')



class SfLogExp(CommonADModel):
    """
    异常处理
    """
    sflog = models.ForeignKey(
        SfLog, on_delete=models.CASCADE, verbose_name='关联值班记录')
    stlog = models.ForeignKey(
        StLog, verbose_name='关联异常记录', on_delete=models.CASCADE)
    duration_sec = models.PositiveIntegerField('持续时长(s)', null=True, blank=True)
    note = models.TextField('处理备注', default='', blank=True)

    class Meta:
        unique_together = ('sflog', 'stlog')

class WmStateOption(models.IntegerChoices):
    OK = 10, _("合格")
    NOTOK = 20, _("不合格")
    REPAIR = 30, _("返修")
    TEST = 40, _("检验")
    SCRAP = 50, _("报废")

class WMaterial(CommonBDModel):
    """
    belong_dept是所在车间
    """
    WM_OK = 10
    WM_NOTOK = 20
    WM_REPAIR = 30
    WM_TEST = 40
    WM_SCRAP = 50
    state = models.PositiveSmallIntegerField('状态', default=10, choices=((10, '合格'), (20, '不合格'), (30, '返修'), (40, '检验'), (50, '报废')))
    material = models.ForeignKey(
        Material, verbose_name='物料', on_delete=models.CASCADE, related_name='wm_m')
    supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True)
    mgroup = models.ForeignKey(Mgroup, verbose_name='所在工段', on_delete=models.CASCADE, null=True, blank=True)
    batch = models.TextField('批次号')
    count = models.PositiveIntegerField('当前数量', default=0)
    count_eweight = models.FloatField('单数重量', default=0)
    defect = models.ForeignKey('qm.defect', verbose_name='缺陷', on_delete=models.SET_NULL, null=True, blank=True)
    notok_sign = models.CharField('不合格标记', max_length=10, null=True, blank=True)
    material_origin = models.ForeignKey(Material, verbose_name='原始物料', on_delete=models.SET_NULL, null=True, blank=True, related_name='wm_mo')
    count_xtest = models.PositiveIntegerField('已检数量', null=True, blank=True)
    batch_ofrom = models.TextField('原料批次号', null=True, blank=True)
    material_ofrom = models.ForeignKey(Material, verbose_name='原料物料', on_delete=models.SET_NULL, null=True, blank=True, related_name='wm_mofrom')

    @property
    def count_working(self):
        return Mlogb.objects.filter(wm_in=self, mlog__work_end_time__isnull=True).aggregate(count=Sum('count_use'))['count'] or 0

    @classmethod
    def mat_in_qs(cls, mtask: Mtask, qs=None):
        """
        可用于该子任务的queryset
        """
        if qs is None:
            qs = cls.objects
        return qs.filter(
                mgroup=mtask.mgroup,
                material=mtask.material_in,
                batch__in=Subquery(
                    Mlogb.objects.filter(
                        mtask__utask=mtask.utask,
                        mlog__submit_time__isnull=False,
                        material_out=mtask.material_in
                    ).values_list('batch', flat=True)
                ),
                state__in=[WMaterial.WM_OK, WMaterial.WM_REPAIR]
            )
    
class Fmlog(CommonADModel):
    mtask = models.ForeignKey(Mtask, verbose_name='任务', on_delete=models.CASCADE, related_name='fmlog_mtask')
    mgroup = models.ForeignKey(Mgroup, verbose_name='工段', on_delete=models.CASCADE, related_name='fmlog_mgroup')
    note = models.TextField('备注', default='', blank=True)

class Mlog(CommonADModel):
    """
    生产日志
    """
    # 变成父级的字段
    MLOG_2 = 10
    MLOG_23 = 20
    MLOG_12 = 30
    MTYPE_SELF = 10
    MTYPE_OUT = 20
    fmlog = models.ForeignKey(Fmlog, verbose_name='关联生产日志', on_delete=models.SET_NULL, null=True, blank=True, related_name='mlog_fmlog')
    mtaskb  = models.ForeignKey(Mtaskb, verbose_name='关联个人任务', on_delete=models.CASCADE, related_name='mlog_mtaskb', null=True, blank=True)
    fill_way = models.PositiveSmallIntegerField("填写方式", default=10, help_text='10:仅二级;20:二三级;30:一二级')
    mtype = models.PositiveSmallIntegerField('生产类型', default=10, help_text='10:自生产;20:外协生产', choices=((10, '自生产'), (20, '外协生产')))
    supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True)
    work_start_time = models.DateTimeField('生产开始时间', null=True, blank=True)
    work_end_time = models.DateTimeField('生产结束时间', null=True, blank=True)
    hour_work = models.FloatField('预计工时', null=True, blank=True)
    reminder_interval_list = models.JSONField('提醒间隔', default=list, blank=True)
    stored_mgroup = models.BooleanField('入库到工段', default=False)
    stored_notok = models.BooleanField('不合格品是否已入库', default=False)
    route = models.ForeignKey(Route, verbose_name='生产路线', on_delete=models.SET_NULL, null=True, blank=True)
    mtask = models.ForeignKey(
        Mtask, verbose_name='关联任务', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_mtask')
    mgroup = models.ForeignKey(
        Mgroup, verbose_name='工段', on_delete=models.CASCADE, null=True, blank=True)
    wm_in = models.ForeignKey(WMaterial, verbose_name='投入物料所在库存', on_delete=models.SET_NULL, null=True, blank=True, related_name='mlog_wm_in')
    material_in = models.ForeignKey(
        Material, verbose_name='消耗物', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_material_in')
    material_out = models.ForeignKey(
        Material, verbose_name='产物', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_material_out')
    equipment = models.ForeignKey(
        Equipment, verbose_name='生产设备', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_equipment')
    equipment_2 = models.ForeignKey(
        Equipment, verbose_name='生产设备2', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_equipment_2')
    equipments = models.ManyToManyField(
        Equipment, verbose_name='多选生产设备', blank=True)
    index = models.PositiveSmallIntegerField('第几锅', default=0)

    shift = models.ForeignKey(
        Shift, verbose_name='关联班次', on_delete=models.SET_NULL, null=True, blank=True)
    batch = models.TextField('批次号', null=True, blank=True)
    count_use = models.PositiveIntegerField('领用数', default=0)
    count_real = models.PositiveIntegerField('实际生产数', default=0)
    count_real_eweight = models.FloatField('单数重量', default=0)
    count_break = models.PositiveIntegerField('加工碎料数', default=0)

    count_ok = models.PositiveIntegerField('合格数', default=0)
    count_notok = models.PositiveIntegerField('不合格数', default=0)
    count_break_t = models.PositiveIntegerField('检验碎料数', default=0)

    count_pn_jgqbl = models.PositiveIntegerField('加工前不良', default=0)
    count_n_zw = models.PositiveIntegerField('炸纹', default=0)
    count_n_tw = models.PositiveIntegerField('条纹', default=0)
    count_n_qp = models.PositiveIntegerField('气泡', default=0)
    count_n_wq = models.PositiveIntegerField('弯曲', default=0)
    count_n_dl = models.PositiveIntegerField('断裂', default=0)
    count_n_pb = models.PositiveIntegerField('偏壁', default=0)
    count_n_dxt = models.PositiveIntegerField('大小头', default=0)
    count_n_js = models.PositiveIntegerField('结石', default=0)
    count_n_qx = models.PositiveIntegerField('气线', default=0)
    count_n_hs = models.PositiveIntegerField('划伤', default=0)
    count_n_cs = models.PositiveIntegerField('挫伤', default=0)
    count_n_bl = models.PositiveIntegerField('不亮', default=0)
    count_n_zz = models.PositiveIntegerField('杂质', default=0)
    count_n_d = models.PositiveIntegerField('短', default=0)
    count_n_zdd = models.PositiveIntegerField('锥度大', default=0)
    count_n_hw = models.PositiveIntegerField('横纹', default=0)
    count_n_yp = models.PositiveIntegerField('有皮', default=0)
    count_n_bp = models.PositiveIntegerField('爆皮', default=0)
    count_n_sc = models.PositiveIntegerField('色差', default=0)
    count_n_tydd = models.PositiveIntegerField('椭圆度大', default=0)
    count_n_sw = models.PositiveIntegerField('水雾', default=0)
    count_n_zjx = models.PositiveIntegerField('直径小', default=0)
    count_n_zjd = models.PositiveIntegerField('直径大', default=0)
    count_n_bhpcd = models.PositiveIntegerField('壁厚偏差大', default=0)
    count_n_xzp = models.PositiveIntegerField('箱中破', default=0)
    count_n_thhs = models.PositiveIntegerField('退火后碎', default=0)
    count_n_swen = models.PositiveIntegerField('水纹', default=0)
    count_n_bb = models.PositiveIntegerField('崩边', default=0)
    count_n_xbb = models.PositiveIntegerField('小崩边', default=0)
    count_n_wm = models.PositiveIntegerField('雾面', default=0)
    count_n_md = models.PositiveIntegerField('麻点', default=0)
    count_n_xh = models.PositiveIntegerField('线痕', default=0)
    count_n_ps = models.PositiveIntegerField('破损', default=0)
    count_n_wj = models.PositiveIntegerField('外经', default=0)
    count_n_yd = models.PositiveIntegerField('圆度', default=0)
    count_n_txd = models.PositiveIntegerField('同心度', default=0)
    count_n_hd = models.PositiveIntegerField('厚度', default=0)
    count_n_zt = models.PositiveIntegerField('炸头', default=0)
    count_n_b = models.PositiveIntegerField('扁', default=0)   # 光芯七车间
    count_n_qt = models.PositiveIntegerField('其他', default=0)

    handle_date = models.DateField('操作日期', null=True, blank=True)
    handle_user = models.ForeignKey(
        User, verbose_name='操作人', on_delete=models.CASCADE, related_name='mlog_handle_user', null=True, blank=True)  # 成型人
    handle_user_2 = models.ForeignKey(
        User, verbose_name='操作人2', on_delete=models.CASCADE, related_name='mlog_handle_user_2', null=True, blank=True)  # 切料人
    handle_users = models.ManyToManyField(
        User, verbose_name='操作人(多选)', blank=True)
    handle_leader = models.ForeignKey(
        User, verbose_name='班长', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_handle_leader')
    note = models.TextField('备注', default='', blank=True)
    material_outs = models.ManyToManyField(
        Material, verbose_name='多个产出', blank=True, through='wpm.mlogb', related_name='mlog_material_outs', through_fields=('mlog', 'material_out'))

    submit_time = models.DateTimeField('提交时间', null=True, blank=True)
    submit_user = models.ForeignKey(
        User, verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_submit_user')

    oinfo_json = models.JSONField('其他信息', default=dict, blank=True)
    ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单',
                               on_delete=models.SET_NULL, related_name='mlog_ticket', null=True, blank=True, db_constraint=False)
    test_file = models.TextField('检验文件', null=True, blank=True)
    test_user = models.ForeignKey(
        User, verbose_name='检验人', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_test_user')
    test_time = models.DateTimeField('检验时间', null=True, blank=True)

    @property
    def mlogb(self):
        return Mlogb.objects.filter(mlog=self).exclude(material_out=None)
    
    @property
    def mlogb_full(self):
        return Mlogb.objects.filter(mlog=self)
    
    @property
    def audit_ignore_fields(self):
        return ['create_by', 'update_by',
                'create_time', 'update_time', 'id']
    
    @classmethod
    def count_fields(cls):
        mlog_count_fields = []
        for f in Mlog._meta.fields:
            if f.name.startswith("count"):
                mlog_count_fields.append(f.name)
        mlog_count_fields.remove("count_real_eweight")
        return mlog_count_fields

class Mlogb(BaseModel):
    qct = models.ForeignKey("qm.qct", verbose_name='所用质检表', on_delete=models.SET_NULL, null=True, blank=True)
    mlog = models.ForeignKey(Mlog, verbose_name='关联日志',
                             on_delete=models.CASCADE, related_name='b_mlog')
    note = models.TextField('备注', default='', blank=True)
    batch = models.TextField('批次号', null=True, blank=True)
    mtask = models.ForeignKey(Mtask, verbose_name='关联任务',
                              on_delete=models.CASCADE, related_name='mlogb_mtask', null=True, blank=True)

    wm_in = models.ForeignKey(WMaterial, verbose_name='投入物料所在库存', on_delete=models.SET_NULL, null=True, blank=True)
    material_in = models.ForeignKey(
        Material, verbose_name='投入物料', on_delete=models.CASCADE, related_name='mlogb_material_in',
        null=True, blank=True)

    parent = models.ForeignKey("self", verbose_name='父级物料', on_delete=models.CASCADE, null=True, blank=True,
                               related_name='mlogb_parent')
    mlogb_to = models.ForeignKey("self", verbose_name='生成的', on_delete=models.SET_NULL, null=True, blank=True,
                                 related_name='mlogb_to_mlogb')
    material_out = models.ForeignKey(
        Material, verbose_name='产物', on_delete=models.CASCADE, related_name='mlogb_material_out',
        null=True, blank=True)

    batch_ofrom = models.TextField('原料批次号', null=True, blank=True)
    material_ofrom = models.ForeignKey(Material, verbose_name='原料物料', on_delete=models.SET_NULL,
                                       null=True, blank=True, related_name='mlogb_mofrom')

    count_use = models.PositiveIntegerField('领用数量', default=0)
    count_break = models.PositiveIntegerField('加工破碎数', default=0)

    count_break_t = models.PositiveIntegerField('检验碎料数', default=0)
    count_real = models.PositiveIntegerField('实际生产数', default=0)
    count_ok = models.PositiveIntegerField('合格数量', default=0)
    count_notok = models.PositiveIntegerField('不合格数', default=0)

    count_pn_jgqbl = models.PositiveIntegerField('加工前不良', default=0)
    # 添加不合格字段后需要更改cal_mlog_count_from_mlogb
    count_n_hs = models.PositiveIntegerField('划伤', default=0)
    count_n_qp = models.PositiveIntegerField('气泡', default=0)
    count_n_swen = models.PositiveIntegerField('水纹', default=0)
    count_n_bb = models.PositiveIntegerField('崩边', default=0)
    count_n_xbb = models.PositiveIntegerField('小崩边', default=0)
    count_n_wm = models.PositiveIntegerField('雾面', default=0)
    count_n_md = models.PositiveIntegerField('麻点', default=0)
    count_n_xh = models.PositiveIntegerField('线痕', default=0)
    count_n_ps = models.PositiveIntegerField('破损', default=0)
    count_n_wj = models.PositiveIntegerField('外经', default=0)
    count_n_yd = models.PositiveIntegerField('圆度', default=0)
    count_n_txd = models.PositiveIntegerField('同心度', default=0)
    count_n_hd = models.PositiveIntegerField('厚度', default=0)
    count_n_zt = models.PositiveIntegerField('炸头', default=0)
    count_n_qt = models.PositiveIntegerField('其他', default=0)
    count_notok_json = models.JSONField('不合格情况', default=list, blank=True)
    def get_tracking(self):
        if self.material_in:
            return "in", self.material_in.tracking
        elif self.material_out:
            return "out", self.material_out.tracking

class Mlogbw(BaseModel):
    number = models.TextField('单个编号')
    mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE)
    wpr = models.ForeignKey("wpmw.wpr", verbose_name='关联产品', on_delete=models.SET_NULL
                            , related_name='wpr_mlogbw', null=True, blank=True)
    ftest = models.OneToOneField("qm.ftest", verbose_name='关联检验',
                                 on_delete=models.PROTECT, null=True, blank=True, related_name="mlogbw_ftest")
    note = models.TextField('备注', null=True, blank=True)


class Handover(CommonADModel):
    """
    交接记录
    """
    H_NORMAL = 10
    H_REPAIR = 20
    H_TEST = 30
    H_SCRAP = 40
    H_CHANGE = 50
    new_batch = models.TextField('新批次号', null=True, blank=True)
    type = models.PositiveSmallIntegerField('交接类型', choices=[(H_NORMAL, '正常交接'), (H_REPAIR, '返修交接'), (H_TEST, '检验交接'), (H_SCRAP, '报废交接'), (H_CHANGE, '改版交接')], default=H_NORMAL)
    send_date = models.DateField('送料日期')
    send_user = models.ForeignKey(
        User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user')
    send_mgroup = models.ForeignKey(
        Mgroup, verbose_name='送料工段', on_delete=models.CASCADE, null=True, blank=True)
    send_dept = models.ForeignKey(
        Dept, verbose_name='送料部门', on_delete=models.CASCADE, related_name='handover_send_dept')
    batch = models.TextField('批次号', null=True, blank=True)
    material = models.ForeignKey(
        Material, verbose_name='物料', on_delete=models.CASCADE, related_name='h_ma')
    material_changed = models.ForeignKey(Material, verbose_name='变更后物料', on_delete=models.CASCADE, null=True, blank=True, related_name='h_ma_c')
    count = models.PositiveIntegerField('送料数', default=0)
    count_eweight = models.FloatField('单数重量', default=0)
    recive_dept = models.ForeignKey(
        Dept, verbose_name='接收部门', on_delete=models.CASCADE, related_name='handover_recive_dept')
    recive_mgroup = models.ForeignKey(Mgroup, verbose_name='接收工段', on_delete=models.CASCADE, related_name='handover_recive_mgroup', null=True, blank=True)
    recive_user = models.ForeignKey(
        User, verbose_name='接收人', on_delete=models.CASCADE, related_name='handover_recive_user')
    wm = models.ForeignKey(WMaterial, verbose_name='关联车间库存', on_delete=models.SET_NULL,
                           null=True, blank=True, related_name='handover_wm')
    mlog = models.ForeignKey(Mlog, verbose_name='关联日志记录',
                             on_delete=models.SET_NULL, null=True, blank=True, related_name='handover_mlog')
    doin_date = models.DateField('加料日期', null=True, blank=True)
    doout_date = models.DateField('出料日期', null=True, blank=True)

    submit_time = models.DateTimeField('提交时间', null=True, blank=True)
    submit_user = models.ForeignKey(
        User, verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='handover_submit_user')
    note = models.TextField('备注', null=True, blank=True)

    @property
    def handoverb(self):
        return Handoverb.objects.filter(handover=self)

class Handoverb(BaseModel):
    handover = models.ForeignKey(Handover, verbose_name='关联交接记录', on_delete=models.CASCADE)
    wm = models.ForeignKey(WMaterial, verbose_name='关联车间库存', on_delete=models.SET_NULL,
                           null=True, blank=True, related_name='handoverb_wm')
    count = models.PositiveIntegerField('送料数', default=0)

    @property
    def handoverbw(self):
        return Handoverbw.objects.filter(handoverb=self)

class Handoverbw(BaseModel):
    handoverb = models.ForeignKey(Handoverb, verbose_name='关联交接记录', on_delete=models.CASCADE)
    number = models.TextField('单个编号')
    wpr = models.ForeignKey("wpmw.wpr", verbose_name='关联产品', on_delete=models.CASCADE
                            , related_name='wpr_handoverbw', null=True, blank=True)
    note = models.TextField('备注', null=True, blank=True)

class AttLog(CommonADModel):
    """
    到岗记录
    """
    ATT_STATE_CHOICES = [
        ('pending', '待定'),
        ('normal', '正常'),
        ('late', '迟到'),
        ('early_leave', '早退'),
        ('absent', '未到岗'),
        ('leave', '请假'),
        # 可以根据需要添加更多状态
    ]
    sflog = models.ForeignKey(
        SfLog, verbose_name='关联值班记录', on_delete=models.CASCADE)
    user = models.ForeignKey(
        'system.user', verbose_name='到岗人', on_delete=models.CASCADE)
    post = models.ForeignKey(
        'system.post', verbose_name='岗位', on_delete=models.CASCADE)
    state = models.CharField('状态', max_length=20,
                             choices=ATT_STATE_CHOICES, default='pending', help_text=str(ATT_STATE_CHOICES))
    note = models.TextField('备注信息', default='', blank=True)


class OtherLog(CommonADModel):
    """
    其他生产日志
    """
    product = models.CharField('产品', max_length=10)
    handle_date = models.DateField('操作日期')
    count_real = models.PositiveIntegerField('实际生产数', default=0)
    count_ok = models.PositiveIntegerField('合格数', default=0)
    count_delivered = models.PositiveIntegerField('交付数', default=0)
