from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.conf import settings
from django.db import models
from django.core.exceptions import ValidationError

from flower.common import ModelBase


class CapacityUnitEnum(models.IntegerChoices):
    METER = 1, '米'
    YARD = 2, '码'


class ProductionAssignmentStatusEnum(models.IntegerChoices):
    DRAFT = 1, 'Draft'
    PUBLISHED = 2, '已发布'
    ACCEPTED = 3, '已接收'
    CANCELLED = 4, '已取消'
    COMPLETED = 5, '已完工'


class DeviceCategory(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey(
        'basic_info.Merchant',
        on_delete=models.PROTECT,
        related_name='mes_device_categories',
        verbose_name='所属商户',
    )
    name = models.CharField(max_length=100, verbose_name='设备分类名称')
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        related_name='created_mes_device_categories',
        verbose_name='创建人',
    )
    operator = models.ForeignKey(
        'basic_info.Employee',
        on_delete=models.PROTECT,
        related_name='operated_mes_device_categories',
        verbose_name='操作人',
    )

    def __str__(self):
        return self.name

    def clean(self):
        if self.operator_id and self.merchant_id and self.operator.merchant_id != self.merchant_id:
            raise ValidationError({'operator': '操作人不属于当前商户'})

    class Meta:
        verbose_name = '设备分类'
        verbose_name_plural = '设备分类'
        ordering = ['id']
        constraints = [
            models.UniqueConstraint(fields=['merchant', 'name'], name='unique_mes_device_category_name_per_merchant'),
        ]


class Device(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey(
        'basic_info.Merchant',
        on_delete=models.PROTECT,
        related_name='mes_devices',
        verbose_name='所属商户',
    )
    category = models.ForeignKey(
        DeviceCategory,
        on_delete=models.PROTECT,
        related_name='devices',
        verbose_name='设备分类',
    )
    name = models.CharField(max_length=100, verbose_name='设备名称')
    peak_capacity = models.PositiveIntegerField(default=100, verbose_name='峰值产能')
    capacity_unit = models.IntegerField(
        choices=CapacityUnitEnum.choices,
        default=CapacityUnitEnum.METER,
        verbose_name='产能单位',
    )
    extra = models.JSONField(null=True, blank=True, verbose_name='扩展参数')
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        related_name='created_mes_devices',
        verbose_name='创建人',
    )
    operator = models.ForeignKey(
        'basic_info.Employee',
        on_delete=models.PROTECT,
        related_name='operated_mes_devices',
        verbose_name='操作人',
    )

    def __str__(self):
        return self.name

    def clean(self):
        errors = {}
        if self.operator_id and self.merchant_id and self.operator.merchant_id != self.merchant_id:
            errors['operator'] = '操作人不属于当前商户'
        if self.category_id and self.merchant_id and self.category.merchant_id != self.merchant_id:
            errors['category'] = '设备分类不属于当前商户'
        if self.peak_capacity <= 0:
            errors['peak_capacity'] = '峰值产能必须大于0'
        if errors:
            raise ValidationError(errors)

    class Meta:
        verbose_name = '设备'
        verbose_name_plural = '设备'
        ordering = ['id']
        constraints = [
            models.UniqueConstraint(fields=['merchant', 'name'], name='unique_mes_device_name_per_merchant'),
        ]


class ProductionAssignment(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey(
        'basic_info.Merchant',
        on_delete=models.PROTECT,
        related_name='mes_production_assignments',
        verbose_name='所属商户',
    )
    device = models.ForeignKey(
        Device,
        on_delete=models.PROTECT,
        related_name='production_assignments',
        null=True,
        blank=True,
        verbose_name='设备',
    )
    content_type = models.ForeignKey(
        ContentType,
        on_delete=models.PROTECT,
        related_name='mes_production_assignments',
        verbose_name='关联对象类型',
    )
    object_id = models.PositiveBigIntegerField(db_index=True, verbose_name='关联对象ID')
    content_object = GenericForeignKey('content_type', 'object_id')
    assigner = models.ForeignKey(
        'basic_info.Employee',
        on_delete=models.PROTECT,
        related_name='assigned_mes_production_assignments',
        verbose_name='指派者',
    )
    assignee = models.ForeignKey(
        'basic_info.Employee',
        on_delete=models.PROTECT,
        related_name='received_mes_production_assignments',
        null=True,
        blank=True,
        verbose_name='被指派人',
    )
    production_quantity = models.PositiveIntegerField(verbose_name='生产数量')
    status = models.IntegerField(
        choices=ProductionAssignmentStatusEnum.choices,
        default=ProductionAssignmentStatusEnum.DRAFT,
        verbose_name='状态',
    )
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        related_name='created_mes_production_assignments',
        verbose_name='创建人',
    )
    operator = models.ForeignKey(
        'basic_info.Employee',
        on_delete=models.PROTECT,
        related_name='operated_mes_production_assignments',
        verbose_name='操作人',
    )
    extra = models.JSONField(null=True, blank=True, verbose_name='扩展参数')

    def __str__(self):
        return f'ProductionAssignment #{self.id}'

    def clean(self):
        errors = {}
        if self.device_id and self.merchant_id and self.device.merchant_id != self.merchant_id:
            errors['device'] = '设备不属于当前商户'
        if self.assigner_id and self.merchant_id and self.assigner.merchant_id != self.merchant_id:
            errors['assigner'] = '指派者不属于当前商户'
        if self.assignee_id and self.merchant_id and self.assignee.merchant_id != self.merchant_id:
            errors['assignee'] = '被指派人不属于当前商户'
        if self.operator_id and self.merchant_id and self.operator.merchant_id != self.merchant_id:
            errors['operator'] = '操作人不属于当前商户'
        if self.production_quantity is not None and self.production_quantity <= 0:
            errors['production_quantity'] = '生产数量必须大于0'
        if self.content_type_id and self.object_id:
            try:
                content_object = self.content_type.get_object_for_this_type(pk=self.object_id)
            except Exception as exc:
                errors['object_id'] = '关联对象不存在'
            else:
                content_object_merchant_id = getattr(content_object, 'merchant_id', None)
                if content_object_merchant_id is not None and self.merchant_id and content_object_merchant_id != self.merchant_id:
                    errors['object_id'] = '关联对象不属于当前商户'
        if errors:
            raise ValidationError(errors)

    class Meta:
        verbose_name = '生产指派'
        verbose_name_plural = '生产指派'
        ordering = ['-created_at', '-id']
        indexes = [
            models.Index(fields=['merchant', 'content_type', 'object_id']),
            models.Index(fields=['merchant', 'device', 'created_at']),
            models.Index(fields=['merchant', 'status', 'created_at']),
        ]

