from __future__ import annotations
from typing import TYPE_CHECKING

from django.db import models
from django.contrib.auth import get_user_model
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):
    """出货单状态"""
    DRAFT = 1, '草稿(未发布)'
    PUBLISHED = 2, '已发布'
    CANCELLED = 3, '已取消'
    REJECTED = 4, '已驳回'
    APPROVED = 5, '已审核'


class ShipmentDeliveryStatus(models.IntegerChoices):
    """送货单状态"""
    PENDING = 1, '待送货'
    IN_TRANSIT = 2, '送货中'
    DELIVERED = 3, '已送达'
    CANCELLED = 4, '已取消'


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.DRAFT,
        verbose_name='状态',
    )

    status_modified_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='取消人',
    )

    approved_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='approved_shipments',
        verbose_name='审核人',
    )

    delivery = models.ForeignKey(
        'ShipmentDelivery',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='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='实际出货日期'
    )

    address = models.CharField(
        max_length=255,
        blank=True,
        default='',
        verbose_name='地址',
    )

    contact_name = models.CharField(
        max_length=100,
        blank=True,
        default='',
        verbose_name='联系人',
    )

    contact_phone = models.CharField(
        max_length=50,
        blank=True,
        default='',
        verbose_name='联系电话',
    )

    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='创建人'
    )

    geo_coordinates = models.JSONField(
        null=True,
        blank=True,
        verbose_name='地理坐标',
        help_text='由 Geo 系统返回的坐标信息，结构由调用方决定，后端不作校验',
    )

    rejected_sales_item_ids = models.JSONField(
        default=list,
        blank=True,
        verbose_name='驳回前销售品ID快照',
        help_text='仅用于审计，记录出货单驳回前所绑定的销售品ID列表',
    )

    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:
        """
        取消出货单（委托给 service 处理状态机与时间记录）
        
        Args:
            operator: 操作者（通常为 request.user，可为空）
        """
        from shipment.services import modify_status

        modify_status(
            self,
            target_status=ShipmentStatus.CANCELLED,
            operator=operator,
        )


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='备注'
    )

    delete_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='删除时间',
    )

    delete_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='deleted_sales_items',
        verbose_name='删除人',
    )

    merge_remark = models.JSONField(
        null=True,
        blank=True,
        verbose_name='合卷备注',
        help_text='合卷信息JSON，包含 merge_type, jobs, main_job, quantity, unit, job_count',
    )
    
    class Meta:
        db_table = 'sales_item'
        verbose_name = '销售品'
        verbose_name_plural = '销售品'
        ordering = ['id']
        permissions = [
            ('soft_delete_salesitem', 'Can soft delete sales item'),
        ]
    
    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


class SalesItemChangeRecord(ModelBase):
    """
    销售品修改记录。

    记录允许修改字段的变更前后值，以及操作者与操作时间。
    """

    sales_item = models.ForeignKey(
        SalesItem,
        on_delete=models.CASCADE,
        related_name="change_records",
        verbose_name="销售品",
    )

    operator = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="sales_item_change_records",
        verbose_name="操作者",
    )

    operated_at = models.DateTimeField(
        verbose_name="操作时间",
    )

    before_values = models.JSONField(
        default=dict,
        blank=True,
        verbose_name="修改前的值",
    )

    after_values = models.JSONField(
        default=dict,
        blank=True,
        verbose_name="修改目标值",
    )

    class Meta:
        db_table = "sales_item_change_record"
        verbose_name = "销售品修改记录"
        verbose_name_plural = "销售品修改记录"
        ordering = ["-operated_at", "-id"]

    def __str__(self) -> str:
        return f"SalesItemChangeRecord #{self.id} - sales_item={self.sales_item_id}"


class SalesItemRebuildRecord(ModelBase):
    """
    销售品重建记录。

    用于审计“软删除旧销售品并基于新 printing_job 重建销售品”的动作。
    """

    old_sales_item = models.ForeignKey(
        SalesItem,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="rebuild_source_records",
        verbose_name="旧销售品",
    )

    new_sales_item = models.ForeignKey(
        SalesItem,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="rebuild_target_records",
        verbose_name="新销售品",
    )

    operator = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="sales_item_rebuild_records",
        verbose_name="操作者",
    )

    rebuilt_at = models.DateTimeField(
        verbose_name="重建时间",
    )

    old_printing_job_id = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name="旧生产任务ID",
    )

    new_printing_job_id = models.PositiveIntegerField(
        verbose_name="新生产任务ID",
    )

    old_quantity = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        verbose_name="旧数量",
    )

    new_quantity = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        verbose_name="新数量",
    )

    class Meta:
        db_table = "sales_item_rebuild_record"
        verbose_name = "销售品重建记录"
        verbose_name_plural = "销售品重建记录"
        ordering = ["-rebuilt_at", "-id"]

    def __str__(self) -> str:
        return f"SalesItemRebuildRecord #{self.id} - old={self.old_sales_item_id}, new={self.new_sales_item_id}"


class ShipmentDelivery(ModelBase):
    """
    送货单

    记录一次具体送货行为，可关联多个出货单。
    """

    status = models.IntegerField(
        choices=ShipmentDeliveryStatus.choices,
        default=ShipmentDeliveryStatus.PENDING,
        db_index=True,
        verbose_name='状态',
    )

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

    driver_name = models.CharField(
        max_length=100,
        db_index=True,
        verbose_name='司机名',
    )

    vehicle_trip = models.CharField(
        max_length=100,
        db_index=True,
        verbose_name='车次',
    )

    contact_phone = models.CharField(
        max_length=50,
        blank=True,
        default='',
        verbose_name='联系电话',
    )

    vehicle_capacity = models.CharField(
        max_length=100,
        blank=True,
        default='',
        verbose_name='车辆容量',
    )

    remark = models.CharField(
        max_length=200,
        blank=True,
        default='',
        verbose_name='备注',
    )

    internal_remark = models.CharField(
        max_length=200,
        blank=True,
        default='',
        verbose_name='内部备注',
    )

    shipment_order_ids = models.JSONField(
        null=True,
        blank=True,
        default=list,
        verbose_name='出货单顺序ID列表',
        help_text='前端自管的出货单展示顺序，后端不据此重排 shipments 关系',
    )

    started_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='开始送货时间',
    )

    delivered_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='送达时间',
    )

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

    created_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        related_name='created_shipment_deliveries',
        verbose_name='创建人',
    )

    operator = models.ForeignKey(
        basic_models.Employee,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='operated_shipment_deliveries',
        verbose_name='操作人',
    )

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

    class Meta:
        db_table = 'shipment_delivery'
        verbose_name = '送货单'
        verbose_name_plural = '送货单'
        ordering = ['-created_at', '-id']


class ShipmentDeliveryPhoto(ModelBase):
    """司机送达照片，按出货单上传并冗余记录所属送货单。"""

    shipment = models.ForeignKey(
        Shipment,
        on_delete=models.CASCADE,
        related_name='delivery_photos',
        verbose_name='出货单',
    )

    delivery = models.ForeignKey(
        ShipmentDelivery,
        on_delete=models.CASCADE,
        related_name='photos',
        verbose_name='送货单',
    )

    photo = models.ImageField(
        upload_to='shipment_delivery_photos/',
        verbose_name='送达照片',
    )

    remark = models.CharField(
        max_length=200,
        blank=True,
        default='',
        verbose_name='备注',
    )

    created_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        related_name='created_shipment_delivery_photos',
        verbose_name='创建人',
    )

    class Meta:
        db_table = 'shipment_delivery_photo'
        verbose_name = '送达照片'
        verbose_name_plural = '送达照片'
        ordering = ['-created_at', '-id']
        indexes = [
            models.Index(fields=['shipment', 'delivery']),
        ]
        permissions = [
            ('cancel_shipmentdelivery', 'Can cancel shipment delivery'),
        ]

    def __str__(self) -> str:
        return f'送货单 #{self.id} - {self.driver_name} / {self.vehicle_trip}'
