from django.db import models
from apps.system.models import CommonAModel, Dictionary, CommonBModel, CommonADModel, File, BaseModel
from django.db.models import Subquery, OuterRef
from rest_framework.exceptions import ValidationError, ParseError


class Process(CommonBModel):
    """
    工序
    """
    name = models.CharField('工序名称', max_length=100)
    cate = models.CharField('大类', max_length=10, default='')
    sort = models.PositiveSmallIntegerField('排序', default=1)
    instruction = models.ForeignKey(
        File, verbose_name='指导书', on_delete=models.SET_NULL, null=True, blank=True)
    instruction_content = models.TextField('指导书内容', null=True, blank=True)

    class Meta:
        verbose_name = '工序'
        ordering = ['sort', 'create_time']


# Create your models here.
class Material(CommonAModel):
    MA_TYPE_BASE = 0
    MA_TYPE_GOOD = 10
    MA_TYPE_HALFGOOD = 20
    MA_TYPE_MAINSO = 30
    MA_TYPE_HELPSO = 40
    MA_TYPE_TOOL = 50
    MA_TYPE_HELPTOOL = 60
    MA_TYPE_OFFICE = 70

    type_choices = (
        (MA_TYPE_BASE, '电/水/气'),
        (MA_TYPE_GOOD, '成品'),
        (MA_TYPE_HALFGOOD, '半成品'),
        (MA_TYPE_MAINSO, '主要原料'),
        (MA_TYPE_HELPSO, '辅助材料'),
        (MA_TYPE_TOOL, '加工工具'),
        (MA_TYPE_HELPTOOL, '辅助工装'),
        (MA_TYPE_OFFICE, '办公用品')
    )

    name = models.CharField('名称', max_length=50)
    cate = models.CharField('大类', max_length=20, default='', blank=True)
    number = models.CharField('编号', max_length=100, null=True, blank=True)
    model = models.CharField(
        '型号', max_length=100, null=True, blank=True)
    specification = models.CharField(
        '规格', max_length=100, null=True, blank=True)
    code = models.CharField('标识', max_length=50, null=True, blank=True)
    type = models.PositiveSmallIntegerField(
        '物料类型', choices=type_choices, default=1, help_text=str(type_choices))
    testitems = models.JSONField('检测项目', default=list, blank=True)
    sort = models.PositiveSmallIntegerField('排序', default=1)
    unit = models.CharField('基准计量单位', default='个', max_length=10)
    count = models.PositiveIntegerField('物料库存总数', default=0)
    count_safe = models.PositiveIntegerField('安全库存总数', null=True, blank=True)
    process = models.ForeignKey(
        Process, verbose_name='所用工序', on_delete=models.CASCADE, null=True, blank=True)
    parent = models.ForeignKey(
        'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='父物料')
    is_hidden = models.BooleanField('是否隐藏', default=False)
    is_assemb = models.BooleanField('是否组合件', default=False)
    need_route = models.BooleanField('是否需要定义工艺路线', default=False)
    components = models.JSONField('组件', default=dict, null=False, blank=True)
    brothers = models.JSONField('兄弟件', default=list, null=False, blank=True)

    class Meta:
        verbose_name = '物料表'
        ordering = ['sort', '-create_time']

    def __str__(self):
        return f'{self.name}|{self.specification if self.specification else ""}|{self.model if self.model else ""}|{self.process.name if self.process else ""}'


class Shift(CommonBModel):
    """班次
    """
    name = models.CharField('名称', max_length=50)
    rule = models.CharField('所属规则', max_length=10, default='默认')
    start_time_o = models.TimeField('开始时间')
    end_time_o = models.TimeField('结束时间')

    class Meta:
        verbose_name = '班次'


class Team(CommonBModel):
    """班组, belong_dept为所属车间
    """
    name = models.CharField('名称', max_length=50)
    leader = models.ForeignKey(
        'system.user', verbose_name='班长', on_delete=models.CASCADE)


class Mgroup(CommonBModel):
    """测点集
    """

    name = models.CharField('名称', max_length=50)
    cate = models.CharField(
        '分类', max_length=50, default='section', help_text='section/other')  # section是工段
    shift_rule = models.CharField('班次规则', max_length=10, default='默认')
    process = models.ForeignKey(
        Process, verbose_name='工序', on_delete=models.SET_NULL, null=True, blank=True)
    product = models.ForeignKey(
        Material, verbose_name='主要产品', on_delete=models.SET_NULL, null=True, blank=True)
    input_materials = models.JSONField(
        '直接材料', default=list, blank=True, help_text='material的ID列表')
    test_materials = models.JSONField(
        '检测材料', default=list, blank=True, help_text='material的ID列表')
    sort = models.PositiveSmallIntegerField('排序', default=1)
    need_enm = models.BooleanField('是否进行能源监测', default=True)
    is_runing = models.BooleanField('是否正常运行', default=True)

    class Meta:
        verbose_name = '测点集'
        ordering = ['sort', '-create_time']

    def __str__(self) -> str:
        return self.name


class TeamMember(BaseModel):
    team = models.ForeignKey(Team, verbose_name='关联班组',
                             on_delete=models.CASCADE)
    user = models.ForeignKey(
        'system.user', verbose_name='成员', on_delete=models.CASCADE)
    mgroup = models.ForeignKey(
        Mgroup, verbose_name='所在工段', on_delete=models.CASCADE)
    post = models.ForeignKey('system.post', verbose_name='岗位',
                             on_delete=models.SET_NULL, null=True, blank=True)


class Goal(CommonADModel):
    """目标
    """
    mgroup = models.ForeignKey(
        Mgroup, verbose_name='关联工段', on_delete=models.CASCADE, null=True, blank=True)
    year = models.PositiveSmallIntegerField('年')
    goal_cate = models.ForeignKey(
        Dictionary, verbose_name='目标种类', on_delete=models.CASCADE)
    goal_val = models.FloatField('全年目标值')
    goal_val_1 = models.FloatField('1月份目标值')
    goal_val_2 = models.FloatField('2月份目标值')
    goal_val_3 = models.FloatField('3月份目标值')
    goal_val_4 = models.FloatField('4月份目标值')
    goal_val_5 = models.FloatField('5月份目标值')
    goal_val_6 = models.FloatField('6月份目标值')
    goal_val_7 = models.FloatField('7月份目标值')
    goal_val_8 = models.FloatField('8月份目标值')
    goal_val_9 = models.FloatField('9月份目标值')
    goal_val_10 = models.FloatField('10月份目标值')
    goal_val_11 = models.FloatField('11月份目标值')
    goal_val_12 = models.FloatField('12月份目标值')

    class Meta:
        unique_together = ("mgroup", "year", "goal_cate")


class Route(CommonADModel):
    """
    加工路线
    """
    material = models.ForeignKey(
        Material, verbose_name='关联产品', on_delete=models.CASCADE, null=True, blank=True)
    process = models.ForeignKey(
        Process, verbose_name='工序', on_delete=models.CASCADE, null=True, blank=True)
    mgroup = models.ForeignKey(Mgroup, verbose_name='指定工段', on_delete=models.CASCADE,
                               null=True, blank=True, related_name='route_mgroup')
    sort = models.PositiveSmallIntegerField('顺序', default=1)
    is_autotask = models.BooleanField('是否自动排产', default=False)
    material_in = models.ForeignKey(
        Material, verbose_name='主要输入物料', on_delete=models.CASCADE, related_name='route_material_in', null=True, blank=True)
    material_out = models.ForeignKey(
        Material, verbose_name='主要输出物料', on_delete=models.CASCADE, related_name='route_material_out', null=True, blank=True)
    is_count_utask = models.BooleanField('是否主任务统计', default=False)
    out_rate = models.FloatField('出材率', default=100, blank=True)

    @staticmethod
    def get_routes(material: Material, autotask: bool = False):
        """
        返回工艺路线带车间
        """
        kwargs = {'material': material}
        # 校验工艺路线是否正常
        rq = Route.objects.filter(
            **kwargs).order_by('sort', 'process__sort', 'create_time')
        if rq.first().material_in is None or rq.last().material_out is None or rq.last().material_out != rq.last().material:
            raise ParseError('首步缺少输入/最后一步缺少输出')
        if not rq.filter(is_count_utask=True).exists():
            raise ParseError('未指定统计步骤')
        if autotask:
            kwargs['is_autotask'] = True
        return rq
