from __future__ import annotations
from typing import TYPE_CHECKING

from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
from flower.common import ModelBase
from basic_info import models as basic_models

if TYPE_CHECKING:
    from printing.models import PrintingJob

User = get_user_model()


class UnitChoices(models.IntegerChoices):
    """销售品单位"""
    METER = 1, '米'
    PIECE = 2, '件'
    YARD = 3, '码'
    UNIT = 4, '个'


class ShipmentStatus(models.IntegerChoices):
    """出货单状态"""
    PENDING_DELIVERY = 1, '待送货'
    DELIVERED = 2, '已交付'
    CANCELLED = 3, '已取消'


class ExternalFinishedProduct(ModelBase):
    """
    外部成品表
    
    用于兼容外部遗留系统的数据映射（可被多个出货单引用）。
    """
    style_name = models.CharField(
        max_length=200,
        verbose_name='款式名称',
    )
    num_of_rolls = models.PositiveIntegerField(
        verbose_name='卷数',
    )
    remark = models.CharField(
        max_length=200,
        null=True,
        blank=True,
        verbose_name='备注',
    )
    created_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        related_name='created_external_finished_products',
        verbose_name='创建人',
    )
    shipment = models.ForeignKey(
        'Shipment',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='external_finished_products',
        verbose_name='出货单',
        help_text='关联的出货单（可空，兼容历史数据/逐步迁移）',
    )

    class Meta:
        db_table = 'external_finished_product'
        verbose_name = '外部成品表'
        verbose_name_plural = '外部成品表'
        ordering = ['-created_at']

    def __str__(self) -> str:
        return f'{self.style_name} ({self.num_of_rolls}卷)'


class Shipment(ModelBase):
    """
    出货单
    
    记录一次出货操作，包含多个销售品。
    """
    status = models.IntegerField(
        choices=ShipmentStatus.choices,
        default=ShipmentStatus.PENDING_DELIVERY,
        verbose_name='状态',
    )

    cancelled_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='取消时间',
    )

    cancelled_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='cancelled_shipments',
        verbose_name='取消人',
    )

    external_id = models.CharField(
        max_length=120,
        null=True,
        blank=True,
        verbose_name='外部订单号',
        help_text='用于兼容外部遗留系统的订单号（可空）',
    )

    merchant = models.ForeignKey(
        basic_models.Merchant,
        on_delete=models.PROTECT,
        related_name='shipments',
        verbose_name='所属商户',
    )

    customer = models.ForeignKey(
        basic_models.Customer,
        on_delete=models.PROTECT,
        related_name='shipments',
        verbose_name='客户'
    )
    
    shipment_date = models.DateField(
        verbose_name='出货日期',
        help_text='实际出货日期'
    )

    area = models.CharField(
        max_length=30,
        blank=True,
        default='',
        verbose_name='地区',
        help_text='出货地区（可空字符串）',
    )
    
    remark = models.TextField(
        blank=True,
        default='',
        verbose_name='备注'
    )
    
    created_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        related_name='created_shipments',
        verbose_name='创建人'
    )
    
    class Meta:
        db_table = 'shipment'
        verbose_name = '出货单'
        verbose_name_plural = '出货单'
        ordering = ['-created_at']
    
    def __str__(self):
        return f'出货单 #{self.id} - {self.customer.name}'

    def cancel(self, operator: User | None) -> None:
        """
        取消出货单（记录取消时间与操作者）
        
        Args:
            operator: 操作者（通常为 request.user，可为空）
        """
        self.status = ShipmentStatus.CANCELLED
        self.cancelled_at = timezone.now()
        self.cancelled_by = operator
        self.save(update_fields=['status', 'cancelled_at', 'cancelled_by', 'updated_at'])


class SalesItem(ModelBase):
    """
    销售品
    
    出货单中的具体商品明细。
    销售品可以先创建（待分配状态），后续再关联到出货单。
    """
    shipment = models.ForeignKey(
        Shipment,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='items',
        verbose_name='出货单',
        help_text='为空表示待分配'
    )

    merchant = models.ForeignKey(
        basic_models.Merchant,
        on_delete=models.PROTECT,
        related_name='sales_items',
        verbose_name='所属商户',
    )
    
    name = models.CharField(
        max_length=200,
        verbose_name='名称'
    )
    
    quantity = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        verbose_name='数量'
    )
    
    unit = models.IntegerField(
        choices=UnitChoices.choices,
        default=UnitChoices.PIECE,
        verbose_name='单位'
    )
    
    created_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        related_name='created_sales_items',
        verbose_name='创建人'
    )
    
    # 关联的生产明细订单（可空）
    # 使用 PositiveIntegerField 而非 ForeignKey，避免模块间强依赖
    printing_job_id = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name='关联生产任务ID',
        help_text='关联的 PrintingJob ID（可空）'
    )
    
    # 客户ID（可空，用于销售品级别的客户关联）
    customer_id = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name='客户ID',
        help_text='销售品级别的客户ID（可空）'
    )
    
    position = models.CharField(
        max_length=200,
        blank=True,
        default='',
        verbose_name='货位'
    )
    
    remark = models.CharField(
        max_length=200,
        blank=True,
        default='',
        verbose_name='备注'
    )
    
    class Meta:
        db_table = 'sales_item'
        verbose_name = '销售品'
        verbose_name_plural = '销售品'
        ordering = ['id']
    
    def __str__(self):
        return f'{self.name} x {self.quantity} {self.get_unit_display()}'
    
    def get_printing_job(self) -> PrintingJob | None:
        """
        获取关联的 PrintingJob 实例
        
        Returns:
            PrintingJob 实例，如果不存在则返回 None
        """
        if not self.printing_job_id:
            return None
        try:
            from printing.models import PrintingJob
            return PrintingJob.objects.get(id=self.printing_job_id)
        except PrintingJob.DoesNotExist:
            return None
    
    def get_customer(self) -> basic_models.Customer | None:
        """
        获取关联的 Customer 实例
        
        Returns:
            Customer 实例，如果不存在则返回 None
        """
        if not self.customer_id:
            return None
        try:
            return basic_models.Customer.objects.get(id=self.customer_id)
        except basic_models.Customer.DoesNotExist:
            return None
